summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--0000_README4
-rw-r--r--1022_linux-6.1.23.patch10192
2 files changed, 10196 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index dac87a0b..82189ada 100644
--- a/0000_README
+++ b/0000_README
@@ -131,6 +131,10 @@ Patch: 1021_linux-6.1.22.patch
From: https://www.kernel.org
Desc: Linux 6.1.22
+Patch: 1022_linux-6.1.23.patch
+From: https://www.kernel.org
+Desc: Linux 6.1.23
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
diff --git a/1022_linux-6.1.23.patch b/1022_linux-6.1.23.patch
new file mode 100644
index 00000000..885f13e9
--- /dev/null
+++ b/1022_linux-6.1.23.patch
@@ -0,0 +1,10192 @@
+diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
+index 7149784a36ac7..3ee77af5a74cf 100644
+--- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
++++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.yaml
+@@ -84,6 +84,13 @@ patternProperties:
+ "^otp(-[0-9]+)?$":
+ type: object
+
++ spi-cpol: true
++ spi-cpha: true
++
++dependencies:
++ spi-cpol: [ spi-cpha ]
++ spi-cpha: [ spi-cpol ]
++
+ unevaluatedProperties: false
+
+ examples:
+diff --git a/Makefile b/Makefile
+index c3d44de8850cf..a162f6cdf77c6 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 6
+ PATCHLEVEL = 1
+-SUBLEVEL = 22
++SUBLEVEL = 23
+ EXTRAVERSION =
+ NAME = Hurr durr I'ma ninja sloth
+
+diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts
+index fcc890e3ad735..f11feb98fde33 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-ibm-everest.dts
+@@ -244,7 +244,7 @@
+ };
+ };
+
+- iio-hwmon-battery {
++ iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc1 7>;
+ };
+diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
+index 4879da4cdbd25..77a3a27b04e26 100644
+--- a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
++++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
+@@ -220,7 +220,7 @@
+ };
+ };
+
+- iio-hwmon-battery {
++ iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc1 7>;
+ };
+diff --git a/arch/arm64/kernel/efi-header.S b/arch/arm64/kernel/efi-header.S
+index 28d8a5dca5f12..d731b4655df8e 100644
+--- a/arch/arm64/kernel/efi-header.S
++++ b/arch/arm64/kernel/efi-header.S
+@@ -66,7 +66,7 @@
+ .long .Lefi_header_end - .L_head // SizeOfHeaders
+ .long 0 // CheckSum
+ .short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem
+- .short 0 // DllCharacteristics
++ .short IMAGE_DLL_CHARACTERISTICS_NX_COMPAT // DllCharacteristics
+ .quad 0 // SizeOfStackReserve
+ .quad 0 // SizeOfStackCommit
+ .quad 0 // SizeOfHeapReserve
+diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
+index 2c3759f1f2c56..019472dd98ff7 100644
+--- a/arch/arm64/kvm/mmu.c
++++ b/arch/arm64/kvm/mmu.c
+@@ -646,14 +646,33 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
+ CONFIG_PGTABLE_LEVELS),
+ .mm_ops = &kvm_user_mm_ops,
+ };
++ unsigned long flags;
+ kvm_pte_t pte = 0; /* Keep GCC quiet... */
+ u32 level = ~0;
+ int ret;
+
++ /*
++ * Disable IRQs so that we hazard against a concurrent
++ * teardown of the userspace page tables (which relies on
++ * IPI-ing threads).
++ */
++ local_irq_save(flags);
+ ret = kvm_pgtable_get_leaf(&pgt, addr, &pte, &level);
+- VM_BUG_ON(ret);
+- VM_BUG_ON(level >= KVM_PGTABLE_MAX_LEVELS);
+- VM_BUG_ON(!(pte & PTE_VALID));
++ local_irq_restore(flags);
++
++ if (ret)
++ return ret;
++
++ /*
++ * Not seeing an error, but not updating level? Something went
++ * deeply wrong...
++ */
++ if (WARN_ON(level >= KVM_PGTABLE_MAX_LEVELS))
++ return -EFAULT;
++
++ /* Oops, the userspace PTs are gone... Replay the fault */
++ if (!kvm_pte_valid(pte))
++ return -EAGAIN;
+
+ return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(level));
+ }
+@@ -1006,7 +1025,7 @@ static bool fault_supports_stage2_huge_mapping(struct kvm_memory_slot *memslot,
+ *
+ * Returns the size of the mapping.
+ */
+-static unsigned long
++static long
+ transparent_hugepage_adjust(struct kvm *kvm, struct kvm_memory_slot *memslot,
+ unsigned long hva, kvm_pfn_t *pfnp,
+ phys_addr_t *ipap)
+@@ -1018,8 +1037,15 @@ transparent_hugepage_adjust(struct kvm *kvm, struct kvm_memory_slot *memslot,
+ * sure that the HVA and IPA are sufficiently aligned and that the
+ * block map is contained within the memslot.
+ */
+- if (fault_supports_stage2_huge_mapping(memslot, hva, PMD_SIZE) &&
+- get_user_mapping_size(kvm, hva) >= PMD_SIZE) {
++ if (fault_supports_stage2_huge_mapping(memslot, hva, PMD_SIZE)) {
++ int sz = get_user_mapping_size(kvm, hva);
++
++ if (sz < 0)
++ return sz;
++
++ if (sz < PMD_SIZE)
++ return PAGE_SIZE;
++
+ /*
+ * The address we faulted on is backed by a transparent huge
+ * page. However, because we map the compound huge page and
+@@ -1138,7 +1164,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ bool logging_active = memslot_is_logging(memslot);
+ bool use_read_lock = false;
+ unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
+- unsigned long vma_pagesize, fault_granule;
++ long vma_pagesize, fault_granule;
+ enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
+ struct kvm_pgtable *pgt;
+
+@@ -1295,6 +1321,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+ vma_pagesize = transparent_hugepage_adjust(kvm, memslot,
+ hva, &pfn,
+ &fault_ipa);
++
++ if (vma_pagesize < 0) {
++ ret = vma_pagesize;
++ goto out_unlock;
++ }
+ }
+
+ if (fault_status != FSC_PERM && !device && kvm_has_mte(kvm)) {
+diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
+index f4a7c5abcbca4..bfe4f17232b3e 100644
+--- a/arch/arm64/kvm/sys_regs.c
++++ b/arch/arm64/kvm/sys_regs.c
+@@ -767,6 +767,22 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
+ return true;
+ }
+
++static int get_pmu_evcntr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
++ u64 *val)
++{
++ u64 idx;
++
++ if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 0)
++ /* PMCCNTR_EL0 */
++ idx = ARMV8_PMU_CYCLE_IDX;
++ else
++ /* PMEVCNTRn_EL0 */
++ idx = ((r->CRm & 3) << 3) | (r->Op2 & 7);
++
++ *val = kvm_pmu_get_counter_value(vcpu, idx);
++ return 0;
++}
++
+ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+@@ -983,7 +999,7 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+ /* Macro to expand the PMEVCNTRn_EL0 register */
+ #define PMU_PMEVCNTR_EL0(n) \
+ { PMU_SYS_REG(SYS_PMEVCNTRn_EL0(n)), \
+- .reset = reset_pmevcntr, \
++ .reset = reset_pmevcntr, .get_user = get_pmu_evcntr, \
+ .access = access_pmu_evcntr, .reg = (PMEVCNTR0_EL0 + n), }
+
+ /* Macro to expand the PMEVTYPERn_EL0 register */
+@@ -1632,7 +1648,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
+ { PMU_SYS_REG(SYS_PMCEID1_EL0),
+ .access = access_pmceid, .reset = NULL },
+ { PMU_SYS_REG(SYS_PMCCNTR_EL0),
+- .access = access_pmu_evcntr, .reset = reset_unknown, .reg = PMCCNTR_EL0 },
++ .access = access_pmu_evcntr, .reset = reset_unknown,
++ .reg = PMCCNTR_EL0, .get_user = get_pmu_evcntr},
+ { PMU_SYS_REG(SYS_PMXEVTYPER_EL0),
+ .access = access_pmu_evtyper, .reset = NULL },
+ { PMU_SYS_REG(SYS_PMXEVCNTR_EL0),
+diff --git a/arch/mips/bmips/dma.c b/arch/mips/bmips/dma.c
+index 33788668cbdbf..3779e7855bd75 100644
+--- a/arch/mips/bmips/dma.c
++++ b/arch/mips/bmips/dma.c
+@@ -5,6 +5,8 @@
+ #include <asm/bmips.h>
+ #include <asm/io.h>
+
++bool bmips_rac_flush_disable;
++
+ void arch_sync_dma_for_cpu_all(void)
+ {
+ void __iomem *cbr = BMIPS_GET_CBR();
+@@ -15,6 +17,9 @@ void arch_sync_dma_for_cpu_all(void)
+ boot_cpu_type() != CPU_BMIPS4380)
+ return;
+
++ if (unlikely(bmips_rac_flush_disable))
++ return;
++
+ /* Flush stale data out of the readahead cache */
+ cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG);
+ __raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG);
+diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c
+index e95b3f78e7cd4..549a6392a3d2d 100644
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -35,6 +35,8 @@
+ #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c))
+ #define BCM6328_TP1_DISABLED BIT(9)
+
++extern bool bmips_rac_flush_disable;
++
+ static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000;
+
+ struct bmips_quirk {
+@@ -104,6 +106,12 @@ static void bcm6358_quirks(void)
+ * disable SMP for now
+ */
+ bmips_smp_enabled = 0;
++
++ /*
++ * RAC flush causes kernel panics on BCM6358 when booting from TP1
++ * because the bootloader is not initializing it properly.
++ */
++ bmips_rac_flush_disable = !!(read_c0_brcm_cmt_local() & (1 << 31));
+ }
+
+ static void bcm6368_quirks(void)
+diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush.h b/arch/powerpc/include/asm/book3s/64/tlbflush.h
+index 67655cd605456..985bd8e69bdc2 100644
+--- a/arch/powerpc/include/asm/book3s/64/tlbflush.h
++++ b/arch/powerpc/include/asm/book3s/64/tlbflush.h
+@@ -163,6 +163,11 @@ static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,
+ */
+ }
+
++static inline bool __pte_protnone(unsigned long pte)
++{
++ return (pte & (pgprot_val(PAGE_NONE) | _PAGE_RWX)) == pgprot_val(PAGE_NONE);
++}
++
+ static inline bool __pte_flags_need_flush(unsigned long oldval,
+ unsigned long newval)
+ {
+@@ -179,8 +184,8 @@ static inline bool __pte_flags_need_flush(unsigned long oldval,
+ /*
+ * We do not expect kernel mappings or non-PTEs or not-present PTEs.
+ */
+- VM_WARN_ON_ONCE(oldval & _PAGE_PRIVILEGED);
+- VM_WARN_ON_ONCE(newval & _PAGE_PRIVILEGED);
++ VM_WARN_ON_ONCE(!__pte_protnone(oldval) && oldval & _PAGE_PRIVILEGED);
++ VM_WARN_ON_ONCE(!__pte_protnone(newval) && newval & _PAGE_PRIVILEGED);
+ VM_WARN_ON_ONCE(!(oldval & _PAGE_PTE));
+ VM_WARN_ON_ONCE(!(newval & _PAGE_PTE));
+ VM_WARN_ON_ONCE(!(oldval & _PAGE_PRESENT));
+diff --git a/arch/powerpc/kernel/ptrace/ptrace-view.c b/arch/powerpc/kernel/ptrace/ptrace-view.c
+index 076d867412c70..31876db8e996f 100644
+--- a/arch/powerpc/kernel/ptrace/ptrace-view.c
++++ b/arch/powerpc/kernel/ptrace/ptrace-view.c
+@@ -290,6 +290,9 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
+ static int ppr_get(struct task_struct *target, const struct user_regset *regset,
+ struct membuf to)
+ {
++ if (!target->thread.regs)
++ return -EINVAL;
++
+ return membuf_write(&to, &target->thread.regs->ppr, sizeof(u64));
+ }
+
+@@ -297,6 +300,9 @@ static int ppr_set(struct task_struct *target, const struct user_regset *regset,
+ unsigned int pos, unsigned int count, const void *kbuf,
+ const void __user *ubuf)
+ {
++ if (!target->thread.regs)
++ return -EINVAL;
++
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &target->thread.regs->ppr, 0, sizeof(u64));
+ }
+diff --git a/arch/powerpc/platforms/pseries/vas.c b/arch/powerpc/platforms/pseries/vas.c
+index 4ad6e510d405f..94c023bb13e05 100644
+--- a/arch/powerpc/platforms/pseries/vas.c
++++ b/arch/powerpc/platforms/pseries/vas.c
+@@ -857,6 +857,13 @@ int pseries_vas_dlpar_cpu(void)
+ {
+ int new_nr_creds, rc;
+
++ /*
++ * NX-GZIP is not enabled. Nothing to do for DLPAR event
++ */
++ if (!copypaste_feat)
++ return 0;
++
++
+ rc = h_query_vas_capabilities(H_QUERY_VAS_CAPABILITIES,
+ vascaps[VAS_GZIP_DEF_FEAT_TYPE].feat,
+ (u64)virt_to_phys(&hv_cop_caps));
+@@ -1013,6 +1020,7 @@ static int __init pseries_vas_init(void)
+ * Linux supports user space COPY/PASTE only with Radix
+ */
+ if (!radix_enabled()) {
++ copypaste_feat = false;
+ pr_err("API is supported only with radix page tables\n");
+ return -ENOTSUPP;
+ }
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index ae11d5647f9d4..06b9b2f60b9fb 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -278,7 +278,7 @@ config ARCH_RV64I
+ select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
+ select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
+ select HAVE_FUNCTION_GRAPH_TRACER
+- select HAVE_FUNCTION_TRACER if !XIP_KERNEL
++ select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION
+ select SWIOTLB if MMU
+
+ endchoice
+diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c
+index ad34519c8a13d..3ac2ff6a65dac 100644
+--- a/arch/riscv/kvm/vcpu_timer.c
++++ b/arch/riscv/kvm/vcpu_timer.c
+@@ -147,10 +147,8 @@ static void kvm_riscv_vcpu_timer_blocking(struct kvm_vcpu *vcpu)
+ return;
+
+ delta_ns = kvm_riscv_delta_cycles2ns(t->next_cycles, gt, t);
+- if (delta_ns) {
+- hrtimer_start(&t->hrt, ktime_set(0, delta_ns), HRTIMER_MODE_REL);
+- t->next_set = true;
+- }
++ hrtimer_start(&t->hrt, ktime_set(0, delta_ns), HRTIMER_MODE_REL);
++ t->next_set = true;
+ }
+
+ static void kvm_riscv_vcpu_timer_unblocking(struct kvm_vcpu *vcpu)
+diff --git a/arch/s390/Makefile b/arch/s390/Makefile
+index b3235ab0ace83..ed646c583e4fe 100644
+--- a/arch/s390/Makefile
++++ b/arch/s390/Makefile
+@@ -162,7 +162,7 @@ vdso_prepare: prepare0
+
+ ifdef CONFIG_EXPOLINE_EXTERN
+ modules_prepare: expoline_prepare
+-expoline_prepare:
++expoline_prepare: scripts
+ $(Q)$(MAKE) $(build)=arch/s390/lib/expoline arch/s390/lib/expoline/expoline.o
+ endif
+ endif
+diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c
+index 720036fb19242..d44214072779e 100644
+--- a/arch/s390/lib/uaccess.c
++++ b/arch/s390/lib/uaccess.c
+@@ -172,7 +172,7 @@ unsigned long __clear_user(void __user *to, unsigned long size)
+ "4: slgr %0,%0\n"
+ "5:\n"
+ EX_TABLE(0b,2b) EX_TABLE(6b,2b) EX_TABLE(3b,5b) EX_TABLE(7b,5b)
+- : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
++ : "+&a" (size), "+&a" (to), "+a" (tmp1), "=&a" (tmp2)
+ : "a" (empty_zero_page), [spec] "d" (spec.val)
+ : "cc", "memory", "0");
+ return size;
+diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
+index 3c5b52fbe4a7f..a9ec8c9f5c5dd 100644
+--- a/arch/x86/xen/Makefile
++++ b/arch/x86/xen/Makefile
+@@ -45,6 +45,6 @@ obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
+
+ obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
+
+-obj-$(CONFIG_XEN_PV_DOM0) += vga.o
++obj-$(CONFIG_XEN_DOM0) += vga.o
+
+ obj-$(CONFIG_XEN_EFI) += efi.o
+diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
+index 8944726255c9c..333539bdbdaae 100644
+--- a/arch/x86/xen/enlighten_pv.c
++++ b/arch/x86/xen/enlighten_pv.c
+@@ -1389,7 +1389,8 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
+
+ x86_platform.set_legacy_features =
+ xen_dom0_set_legacy_features;
+- xen_init_vga(info, xen_start_info->console.dom0.info_size);
++ xen_init_vga(info, xen_start_info->console.dom0.info_size,
++ &boot_params.screen_info);
+ xen_start_info->console.domU.mfn = 0;
+ xen_start_info->console.domU.evtchn = 0;
+
+diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c
+index bcae606bbc5cf..ada3868c02c23 100644
+--- a/arch/x86/xen/enlighten_pvh.c
++++ b/arch/x86/xen/enlighten_pvh.c
+@@ -43,6 +43,19 @@ void __init xen_pvh_init(struct boot_params *boot_params)
+ x86_init.oem.banner = xen_banner;
+
+ xen_efi_init(boot_params);
++
++ if (xen_initial_domain()) {
++ struct xen_platform_op op = {
++ .cmd = XENPF_get_dom0_console,
++ };
++ int ret = HYPERVISOR_platform_op(&op);
++
++ if (ret > 0)
++ xen_init_vga(&op.u.dom0_console,
++ min(ret * sizeof(char),
++ sizeof(op.u.dom0_console)),
++ &boot_params->screen_info);
++ }
+ }
+
+ void __init mem_map_via_hcall(struct boot_params *boot_params_p)
+diff --git a/arch/x86/xen/vga.c b/arch/x86/xen/vga.c
+index 14ea32e734d59..d97adab8420f4 100644
+--- a/arch/x86/xen/vga.c
++++ b/arch/x86/xen/vga.c
+@@ -9,10 +9,9 @@
+
+ #include "xen-ops.h"
+
+-void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size)
++void __init xen_init_vga(const struct dom0_vga_console_info *info, size_t size,
++ struct screen_info *screen_info)
+ {
+- struct screen_info *screen_info = &boot_params.screen_info;
+-
+ /* This is drawn from a dump from vgacon:startup in
+ * standard Linux. */
+ screen_info->orig_video_mode = 3;
+diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
+index 9a8bb972193d8..a10903785a338 100644
+--- a/arch/x86/xen/xen-ops.h
++++ b/arch/x86/xen/xen-ops.h
+@@ -108,11 +108,12 @@ static inline void xen_uninit_lock_cpu(int cpu)
+
+ struct dom0_vga_console_info;
+
+-#ifdef CONFIG_XEN_PV_DOM0
+-void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size);
++#ifdef CONFIG_XEN_DOM0
++void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size,
++ struct screen_info *);
+ #else
+ static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
+- size_t size)
++ size_t size, struct screen_info *si)
+ {
+ }
+ #endif
+diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
+index 0c25e035ff107..9e9ade20a7ce4 100644
+--- a/arch/xtensa/kernel/traps.c
++++ b/arch/xtensa/kernel/traps.c
+@@ -541,7 +541,7 @@ static size_t kstack_depth_to_print = CONFIG_PRINT_STACK_DEPTH;
+
+ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
+ {
+- size_t len;
++ size_t len, off = 0;
+
+ if (!sp)
+ sp = stack_pointer(task);
+@@ -550,9 +550,17 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
+ kstack_depth_to_print * STACK_DUMP_ENTRY_SIZE);
+
+ printk("%sStack:\n", loglvl);
+- print_hex_dump(loglvl, " ", DUMP_PREFIX_NONE,
+- STACK_DUMP_LINE_SIZE, STACK_DUMP_ENTRY_SIZE,
+- sp, len, false);
++ while (off < len) {
++ u8 line[STACK_DUMP_LINE_SIZE];
++ size_t line_len = len - off > STACK_DUMP_LINE_SIZE ?
++ STACK_DUMP_LINE_SIZE : len - off;
++
++ __memcpy(line, (u8 *)sp + off, line_len);
++ print_hex_dump(loglvl, " ", DUMP_PREFIX_NONE,
++ STACK_DUMP_LINE_SIZE, STACK_DUMP_ENTRY_SIZE,
++ line, line_len, false);
++ off += STACK_DUMP_LINE_SIZE;
++ }
+ show_trace(task, sp, loglvl);
+ }
+
+diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
+index d466c81953146..3b6146b1e25cc 100644
+--- a/drivers/acpi/bus.c
++++ b/drivers/acpi/bus.c
+@@ -456,85 +456,67 @@ out_free:
+ Notification Handling
+ -------------------------------------------------------------------------- */
+
+-/*
+- * acpi_bus_notify
+- * ---------------
+- * Callback for all 'system-level' device notifications (values 0x00-0x7F).
++/**
++ * acpi_bus_notify - Global system-level (0x00-0x7F) notifications handler
++ * @handle: Target ACPI object.
++ * @type: Notification type.
++ * @data: Ignored.
++ *
++ * This only handles notifications related to device hotplug.
+ */
+ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
+ {
+ struct acpi_device *adev;
+- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+- bool hotplug_event = false;
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+- hotplug_event = true;
+ break;
+
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+- hotplug_event = true;
+ break;
+
+ case ACPI_NOTIFY_DEVICE_WAKE:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
+- break;
++ return;
+
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+- hotplug_event = true;
+ break;
+
+ case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
+ /* TBD: Exactly what does 'light' mean? */
+- break;
++ return;
+
+ case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a frequency mismatch\n");
+- break;
++ return;
+
+ case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a bus mode mismatch\n");
+- break;
++ return;
+
+ case ACPI_NOTIFY_POWER_FAULT:
+ acpi_handle_err(handle, "Device has suffered a power fault\n");
+- break;
++ return;
+
+ default:
+ acpi_handle_debug(handle, "Unknown event type 0x%x\n", type);
+- break;
++ return;
+ }
+
+ adev = acpi_get_acpi_dev(handle);
+- if (!adev)
+- goto err;
+-
+- if (adev->dev.driver) {
+- struct acpi_driver *driver = to_acpi_driver(adev->dev.driver);
+-
+- if (driver && driver->ops.notify &&
+- (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
+- driver->ops.notify(adev, type);
+- }
+-
+- if (!hotplug_event) {
+- acpi_put_acpi_dev(adev);
+- return;
+- }
+
+- if (ACPI_SUCCESS(acpi_hotplug_schedule(adev, type)))
++ if (adev && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type)))
+ return;
+
+ acpi_put_acpi_dev(adev);
+
+- err:
+- acpi_evaluate_ost(handle, type, ost_code, NULL);
++ acpi_evaluate_ost(handle, type, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+ }
+
+ static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
+@@ -559,42 +541,51 @@ static u32 acpi_device_fixed_event(void *data)
+ return ACPI_INTERRUPT_HANDLED;
+ }
+
+-static int acpi_device_install_notify_handler(struct acpi_device *device)
++static int acpi_device_install_notify_handler(struct acpi_device *device,
++ struct acpi_driver *acpi_drv)
+ {
+ acpi_status status;
+
+- if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
++ if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
+ status =
+ acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+ acpi_device_fixed_event,
+ device);
+- else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
++ } else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) {
+ status =
+ acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+ acpi_device_fixed_event,
+ device);
+- else
+- status = acpi_install_notify_handler(device->handle,
+- ACPI_DEVICE_NOTIFY,
++ } else {
++ u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
++ ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
++
++ status = acpi_install_notify_handler(device->handle, type,
+ acpi_notify_device,
+ device);
++ }
+
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+ return 0;
+ }
+
+-static void acpi_device_remove_notify_handler(struct acpi_device *device)
++static void acpi_device_remove_notify_handler(struct acpi_device *device,
++ struct acpi_driver *acpi_drv)
+ {
+- if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
++ if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
+ acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+ acpi_device_fixed_event);
+- else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
++ } else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) {
+ acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+ acpi_device_fixed_event);
+- else
+- acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
++ } else {
++ u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
++ ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
++
++ acpi_remove_notify_handler(device->handle, type,
+ acpi_notify_device);
++ }
+ }
+
+ /* Handle events targeting \_SB device (at present only graceful shutdown) */
+@@ -1036,7 +1027,7 @@ static int acpi_device_probe(struct device *dev)
+ acpi_drv->name, acpi_dev->pnp.bus_id);
+
+ if (acpi_drv->ops.notify) {
+- ret = acpi_device_install_notify_handler(acpi_dev);
++ ret = acpi_device_install_notify_handler(acpi_dev, acpi_drv);
+ if (ret) {
+ if (acpi_drv->ops.remove)
+ acpi_drv->ops.remove(acpi_dev);
+@@ -1059,7 +1050,7 @@ static void acpi_device_remove(struct device *dev)
+ struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+
+ if (acpi_drv->ops.notify)
+- acpi_device_remove_notify_handler(acpi_dev);
++ acpi_device_remove_notify_handler(acpi_dev, acpi_drv);
+
+ if (acpi_drv->ops.remove)
+ acpi_drv->ops.remove(acpi_dev);
+diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
+index 7f0ed845cd6ad..f06b3d3556710 100644
+--- a/drivers/acpi/video_detect.c
++++ b/drivers/acpi/video_detect.c
+@@ -714,6 +714,13 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
+ },
+ },
++ {
++ .callback = video_detect_force_native,
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 15 3535"),
++ },
++ },
+
+ /*
+ * Desktops which falsely report a backlight and which our heuristics
+diff --git a/drivers/block/loop.c b/drivers/block/loop.c
+index 793ae876918ce..426d0b42685a0 100644
+--- a/drivers/block/loop.c
++++ b/drivers/block/loop.c
+@@ -1010,9 +1010,6 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
+ /* This is safe, since we have a reference from open(). */
+ __module_get(THIS_MODULE);
+
+- /* suppress uevents while reconfiguring the device */
+- dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 1);
+-
+ /*
+ * If we don't hold exclusive handle for the device, upgrade to it
+ * here to avoid changing device under exclusive owner.
+@@ -1067,6 +1064,9 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
+ }
+ }
+
++ /* suppress uevents while reconfiguring the device */
++ dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 1);
++
+ disk_force_media_change(lo->lo_disk, DISK_EVENT_MEDIA_CHANGE);
+ set_disk_ro(lo->lo_disk, (lo->lo_flags & LO_FLAGS_READ_ONLY) != 0);
+
+@@ -1109,17 +1109,17 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
+ if (partscan)
+ clear_bit(GD_SUPPRESS_PART_SCAN, &lo->lo_disk->state);
+
++ /* enable and uncork uevent now that we are done */
++ dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0);
++
+ loop_global_unlock(lo, is_loop);
+ if (partscan)
+ loop_reread_partitions(lo);
++
+ if (!(mode & FMODE_EXCL))
+ bd_abort_claiming(bdev, loop_configure);
+
+- error = 0;
+-done:
+- /* enable and uncork uevent now that we are done */
+- dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 0);
+- return error;
++ return 0;
+
+ out_unlock:
+ loop_global_unlock(lo, is_loop);
+@@ -1130,7 +1130,7 @@ out_putf:
+ fput(file);
+ /* This is safe: open() is still holding a reference. */
+ module_put(THIS_MODULE);
+- goto done;
++ return error;
+ }
+
+ static void __loop_clr_fd(struct loop_device *lo, bool release)
+diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
+index 4aec9be0ab77e..22a790d512842 100644
+--- a/drivers/block/ublk_drv.c
++++ b/drivers/block/ublk_drv.c
+@@ -656,7 +656,8 @@ static void __ublk_fail_req(struct ublk_queue *ubq, struct ublk_io *io,
+ }
+ }
+
+-static void ubq_complete_io_cmd(struct ublk_io *io, int res)
++static void ubq_complete_io_cmd(struct ublk_io *io, int res,
++ unsigned issue_flags)
+ {
+ /* mark this cmd owned by ublksrv */
+ io->flags |= UBLK_IO_FLAG_OWNED_BY_SRV;
+@@ -668,7 +669,7 @@ static void ubq_complete_io_cmd(struct ublk_io *io, int res)
+ io->flags &= ~UBLK_IO_FLAG_ACTIVE;
+
+ /* tell ublksrv one io request is coming */
+- io_uring_cmd_done(io->cmd, res, 0);
++ io_uring_cmd_done(io->cmd, res, 0, issue_flags);
+ }
+
+ #define UBLK_REQUEUE_DELAY_MS 3
+@@ -685,7 +686,8 @@ static inline void __ublk_abort_rq(struct ublk_queue *ubq,
+ mod_delayed_work(system_wq, &ubq->dev->monitor_work, 0);
+ }
+
+-static inline void __ublk_rq_task_work(struct request *req)
++static inline void __ublk_rq_task_work(struct request *req,
++ unsigned issue_flags)
+ {
+ struct ublk_queue *ubq = req->mq_hctx->driver_data;
+ int tag = req->tag;
+@@ -723,7 +725,7 @@ static inline void __ublk_rq_task_work(struct request *req)
+ pr_devel("%s: need get data. op %d, qid %d tag %d io_flags %x\n",
+ __func__, io->cmd->cmd_op, ubq->q_id,
+ req->tag, io->flags);
+- ubq_complete_io_cmd(io, UBLK_IO_RES_NEED_GET_DATA);
++ ubq_complete_io_cmd(io, UBLK_IO_RES_NEED_GET_DATA, issue_flags);
+ return;
+ }
+ /*
+@@ -761,17 +763,18 @@ static inline void __ublk_rq_task_work(struct request *req)
+ mapped_bytes >> 9;
+ }
+
+- ubq_complete_io_cmd(io, UBLK_IO_RES_OK);
++ ubq_complete_io_cmd(io, UBLK_IO_RES_OK, issue_flags);
+ }
+
+-static inline void ublk_forward_io_cmds(struct ublk_queue *ubq)
++static inline void ublk_forward_io_cmds(struct ublk_queue *ubq,
++ unsigned issue_flags)
+ {
+ struct llist_node *io_cmds = llist_del_all(&ubq->io_cmds);
+ struct ublk_rq_data *data, *tmp;
+
+ io_cmds = llist_reverse_order(io_cmds);
+ llist_for_each_entry_safe(data, tmp, io_cmds, node)
+- __ublk_rq_task_work(blk_mq_rq_from_pdu(data));
++ __ublk_rq_task_work(blk_mq_rq_from_pdu(data), issue_flags);
+ }
+
+ static inline void ublk_abort_io_cmds(struct ublk_queue *ubq)
+@@ -783,12 +786,12 @@ static inline void ublk_abort_io_cmds(struct ublk_queue *ubq)
+ __ublk_abort_rq(ubq, blk_mq_rq_from_pdu(data));
+ }
+
+-static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd)
++static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd, unsigned issue_flags)
+ {
+ struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
+ struct ublk_queue *ubq = pdu->ubq;
+
+- ublk_forward_io_cmds(ubq);
++ ublk_forward_io_cmds(ubq, issue_flags);
+ }
+
+ static void ublk_rq_task_work_fn(struct callback_head *work)
+@@ -797,8 +800,9 @@ static void ublk_rq_task_work_fn(struct callback_head *work)
+ struct ublk_rq_data, work);
+ struct request *req = blk_mq_rq_from_pdu(data);
+ struct ublk_queue *ubq = req->mq_hctx->driver_data;
++ unsigned issue_flags = IO_URING_F_UNLOCKED;
+
+- ublk_forward_io_cmds(ubq);
++ ublk_forward_io_cmds(ubq, issue_flags);
+ }
+
+ static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq)
+@@ -1052,7 +1056,8 @@ static void ublk_cancel_queue(struct ublk_queue *ubq)
+ struct ublk_io *io = &ubq->ios[i];
+
+ if (io->flags & UBLK_IO_FLAG_ACTIVE)
+- io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, 0);
++ io_uring_cmd_done(io->cmd, UBLK_IO_RES_ABORT, 0,
++ IO_URING_F_UNLOCKED);
+ }
+
+ /* all io commands are canceled */
+@@ -1295,7 +1300,7 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
+ return -EIOCBQUEUED;
+
+ out:
+- io_uring_cmd_done(cmd, ret, 0);
++ io_uring_cmd_done(cmd, ret, 0, issue_flags);
+ pr_devel("%s: complete: cmd op %d, tag %d ret %x io_flags %x\n",
+ __func__, cmd_op, tag, ret, io->flags);
+ return -EIOCBQUEUED;
+@@ -2053,7 +2058,7 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
+ break;
+ }
+ out:
+- io_uring_cmd_done(cmd, ret, 0);
++ io_uring_cmd_done(cmd, ret, 0, issue_flags);
+ pr_devel("%s: cmd done ret %d cmd_op %x, dev id %d qid %d\n",
+ __func__, ret, cmd->cmd_op, header->dev_id, header->queue_id);
+ return -EIOCBQUEUED;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+index 435d81d6ffd9b..a78e80f9f65cd 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
+@@ -981,7 +981,12 @@ static bool amdgpu_atcs_pci_probe_handle(struct pci_dev *pdev)
+ */
+ bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev)
+ {
+- if (adev->flags & AMD_IS_APU)
++ if ((adev->flags & AMD_IS_APU) &&
++ adev->gfx.imu.funcs) /* Not need to do mode2 reset for IMU enabled APUs */
++ return false;
++
++ if ((adev->flags & AMD_IS_APU) &&
++ amdgpu_acpi_is_s3_active(adev))
+ return false;
+
+ if (amdgpu_sriov_vf(adev))
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+index f79b8e964140e..e191d38f3da62 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+@@ -1298,14 +1298,14 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
+ args->n_success = i+1;
+ }
+
+- mutex_unlock(&p->mutex);
+-
+ err = amdgpu_amdkfd_gpuvm_sync_memory(dev->adev, (struct kgd_mem *) mem, true);
+ if (err) {
+ pr_debug("Sync memory failed, wait interrupted by user signal\n");
+ goto sync_memory_failed;
+ }
+
++ mutex_unlock(&p->mutex);
++
+ /* Flush TLBs after waiting for the page table updates to complete */
+ for (i = 0; i < args->n_devices; i++) {
+ peer_pdd = kfd_process_device_data_by_id(p, devices_arr[i]);
+@@ -1321,9 +1321,9 @@ get_process_device_data_failed:
+ bind_process_to_device_failed:
+ get_mem_obj_from_handle_failed:
+ map_memory_to_gpu_failed:
++sync_memory_failed:
+ mutex_unlock(&p->mutex);
+ copy_from_user_failed:
+-sync_memory_failed:
+ kfree(devices_arr);
+
+ return err;
+@@ -1337,6 +1337,7 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
+ void *mem;
+ long err = 0;
+ uint32_t *devices_arr = NULL, i;
++ bool flush_tlb;
+
+ if (!args->n_devices) {
+ pr_debug("Device IDs array empty\n");
+@@ -1389,16 +1390,19 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
+ }
+ args->n_success = i+1;
+ }
+- mutex_unlock(&p->mutex);
+
+- if (kfd_flush_tlb_after_unmap(pdd->dev)) {
++ flush_tlb = kfd_flush_tlb_after_unmap(pdd->dev);
++ if (flush_tlb) {
+ err = amdgpu_amdkfd_gpuvm_sync_memory(pdd->dev->adev,
+ (struct kgd_mem *) mem, true);
+ if (err) {
+ pr_debug("Sync memory failed, wait interrupted by user signal\n");
+ goto sync_memory_failed;
+ }
++ }
++ mutex_unlock(&p->mutex);
+
++ if (flush_tlb) {
+ /* Flush TLBs after waiting for the page table updates to complete */
+ for (i = 0; i < args->n_devices; i++) {
+ peer_pdd = kfd_process_device_data_by_id(p, devices_arr[i]);
+@@ -1414,9 +1418,9 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
+ bind_process_to_device_failed:
+ get_mem_obj_from_handle_failed:
+ unmap_memory_from_gpu_failed:
++sync_memory_failed:
+ mutex_unlock(&p->mutex);
+ copy_from_user_failed:
+-sync_memory_failed:
+ kfree(devices_arr);
+ return err;
+ }
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+index 22b077ac9a196..88bf6221d4bef 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+@@ -295,7 +295,7 @@ static unsigned long svm_migrate_unsuccessful_pages(struct migrate_vma *migrate)
+ static int
+ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
+ struct migrate_vma *migrate, struct dma_fence **mfence,
+- dma_addr_t *scratch)
++ dma_addr_t *scratch, uint64_t ttm_res_offset)
+ {
+ uint64_t npages = migrate->npages;
+ struct device *dev = adev->dev;
+@@ -305,19 +305,13 @@ svm_migrate_copy_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
+ uint64_t i, j;
+ int r;
+
+- pr_debug("svms 0x%p [0x%lx 0x%lx]\n", prange->svms, prange->start,
+- prange->last);
++ pr_debug("svms 0x%p [0x%lx 0x%lx 0x%llx]\n", prange->svms, prange->start,
++ prange->last, ttm_res_offset);
+
+ src = scratch;
+ dst = (uint64_t *)(scratch + npages);
+
+- r = svm_range_vram_node_new(adev, prange, true);
+- if (r) {
+- dev_dbg(adev->dev, "fail %d to alloc vram\n", r);
+- goto out;
+- }
+-
+- amdgpu_res_first(prange->ttm_res, prange->offset << PAGE_SHIFT,
++ amdgpu_res_first(prange->ttm_res, ttm_res_offset,
+ npages << PAGE_SHIFT, &cursor);
+ for (i = j = 0; i < npages; i++) {
+ struct page *spage;
+@@ -397,14 +391,14 @@ out_free_vram_pages:
+ migrate->dst[i + 3] = 0;
+ }
+ #endif
+-out:
++
+ return r;
+ }
+
+ static long
+ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
+ struct vm_area_struct *vma, uint64_t start,
+- uint64_t end, uint32_t trigger)
++ uint64_t end, uint32_t trigger, uint64_t ttm_res_offset)
+ {
+ struct kfd_process *p = container_of(prange->svms, struct kfd_process, svms);
+ uint64_t npages = (end - start) >> PAGE_SHIFT;
+@@ -457,7 +451,7 @@ svm_migrate_vma_to_vram(struct amdgpu_device *adev, struct svm_range *prange,
+ else
+ pr_debug("0x%lx pages migrated\n", cpages);
+
+- r = svm_migrate_copy_to_vram(adev, prange, &migrate, &mfence, scratch);
++ r = svm_migrate_copy_to_vram(adev, prange, &migrate, &mfence, scratch, ttm_res_offset);
+ migrate_vma_pages(&migrate);
+
+ pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n",
+@@ -505,6 +499,7 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
+ unsigned long addr, start, end;
+ struct vm_area_struct *vma;
+ struct amdgpu_device *adev;
++ uint64_t ttm_res_offset;
+ unsigned long cpages = 0;
+ long r = 0;
+
+@@ -526,6 +521,13 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
+ start = prange->start << PAGE_SHIFT;
+ end = (prange->last + 1) << PAGE_SHIFT;
+
++ r = svm_range_vram_node_new(adev, prange, true);
++ if (r) {
++ dev_dbg(adev->dev, "fail %ld to alloc vram\n", r);
++ return r;
++ }
++ ttm_res_offset = prange->offset << PAGE_SHIFT;
++
+ for (addr = start; addr < end;) {
+ unsigned long next;
+
+@@ -534,18 +536,21 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc,
+ break;
+
+ next = min(vma->vm_end, end);
+- r = svm_migrate_vma_to_vram(adev, prange, vma, addr, next, trigger);
++ r = svm_migrate_vma_to_vram(adev, prange, vma, addr, next, trigger, ttm_res_offset);
+ if (r < 0) {
+ pr_debug("failed %ld to migrate\n", r);
+ break;
+ } else {
+ cpages += r;
+ }
++ ttm_res_offset += next - addr;
+ addr = next;
+ }
+
+ if (cpages)
+ prange->actual_loc = best_loc;
++ else
++ svm_range_vram_node_free(prange);
+
+ return r < 0 ? r : 0;
+ }
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
+index 09b966dc37681..aee2212e52f69 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
+@@ -77,6 +77,7 @@ err_ioctl:
+
+ static void kfd_exit(void)
+ {
++ kfd_cleanup_processes();
+ kfd_debugfs_fini();
+ kfd_process_destroy_wq();
+ kfd_procfs_shutdown();
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+index bf610e3b683bb..6d6588b9beed7 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+@@ -928,6 +928,7 @@ bool kfd_dev_is_large_bar(struct kfd_dev *dev);
+
+ int kfd_process_create_wq(void);
+ void kfd_process_destroy_wq(void);
++void kfd_cleanup_processes(void);
+ struct kfd_process *kfd_create_process(struct file *filep);
+ struct kfd_process *kfd_get_process(const struct task_struct *task);
+ struct kfd_process *kfd_lookup_process_by_pasid(u32 pasid);
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+index dd351105c1bcf..7f68d51541e8e 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+@@ -1167,6 +1167,17 @@ static void kfd_process_free_notifier(struct mmu_notifier *mn)
+ kfd_unref_process(container_of(mn, struct kfd_process, mmu_notifier));
+ }
+
++static void kfd_process_notifier_release_internal(struct kfd_process *p)
++{
++ cancel_delayed_work_sync(&p->eviction_work);
++ cancel_delayed_work_sync(&p->restore_work);
++
++ /* Indicate to other users that MM is no longer valid */
++ p->mm = NULL;
++
++ mmu_notifier_put(&p->mmu_notifier);
++}
++
+ static void kfd_process_notifier_release(struct mmu_notifier *mn,
+ struct mm_struct *mm)
+ {
+@@ -1181,17 +1192,22 @@ static void kfd_process_notifier_release(struct mmu_notifier *mn,
+ return;
+
+ mutex_lock(&kfd_processes_mutex);
++ /*
++ * Do early return if table is empty.
++ *
++ * This could potentially happen if this function is called concurrently
++ * by mmu_notifier and by kfd_cleanup_pocesses.
++ *
++ */
++ if (hash_empty(kfd_processes_table)) {
++ mutex_unlock(&kfd_processes_mutex);
++ return;
++ }
+ hash_del_rcu(&p->kfd_processes);
+ mutex_unlock(&kfd_processes_mutex);
+ synchronize_srcu(&kfd_processes_srcu);
+
+- cancel_delayed_work_sync(&p->eviction_work);
+- cancel_delayed_work_sync(&p->restore_work);
+-
+- /* Indicate to other users that MM is no longer valid */
+- p->mm = NULL;
+-
+- mmu_notifier_put(&p->mmu_notifier);
++ kfd_process_notifier_release_internal(p);
+ }
+
+ static const struct mmu_notifier_ops kfd_process_mmu_notifier_ops = {
+@@ -1200,6 +1216,43 @@ static const struct mmu_notifier_ops kfd_process_mmu_notifier_ops = {
+ .free_notifier = kfd_process_free_notifier,
+ };
+
++/*
++ * This code handles the case when driver is being unloaded before all
++ * mm_struct are released. We need to safely free the kfd_process and
++ * avoid race conditions with mmu_notifier that might try to free them.
++ *
++ */
++void kfd_cleanup_processes(void)
++{
++ struct kfd_process *p;
++ struct hlist_node *p_temp;
++ unsigned int temp;
++ HLIST_HEAD(cleanup_list);
++
++ /*
++ * Move all remaining kfd_process from the process table to a
++ * temp list for processing. Once done, callback from mmu_notifier
++ * release will not see the kfd_process in the table and do early return,
++ * avoiding double free issues.
++ */
++ mutex_lock(&kfd_processes_mutex);
++ hash_for_each_safe(kfd_processes_table, temp, p_temp, p, kfd_processes) {
++ hash_del_rcu(&p->kfd_processes);
++ synchronize_srcu(&kfd_processes_srcu);
++ hlist_add_head(&p->kfd_processes, &cleanup_list);
++ }
++ mutex_unlock(&kfd_processes_mutex);
++
++ hlist_for_each_entry_safe(p, p_temp, &cleanup_list, kfd_processes)
++ kfd_process_notifier_release_internal(p);
++
++ /*
++ * Ensures that all outstanding free_notifier get called, triggering
++ * the release of the kfd_process struct.
++ */
++ mmu_notifier_synchronize();
++}
++
+ static int kfd_process_init_cwsr_apu(struct kfd_process *p, struct file *filep)
+ {
+ unsigned long offset;
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+index 5137476ec18e6..4236539d9f932 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+@@ -218,8 +218,8 @@ static int init_user_queue(struct process_queue_manager *pqm,
+ return 0;
+
+ cleanup:
+- if (dev->shared_resources.enable_mes)
+- uninit_queue(*q);
++ uninit_queue(*q);
++ *q = NULL;
+ return retval;
+ }
+
+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 8561e9b017a2e..df74bc88e4600 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
+@@ -208,6 +208,21 @@ bool needs_dsc_aux_workaround(struct dc_link *link)
+ return false;
+ }
+
++bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port)
++{
++ u8 branch_vendor_data[4] = { 0 }; // Vendor data 0x50C ~ 0x50F
++
++ if (drm_dp_dpcd_read(port->mgr->aux, DP_BRANCH_VENDOR_SPECIFIC_START, &branch_vendor_data, 4) == 4) {
++ if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
++ IS_SYNAPTICS_CASCADED_PANAMERA(link->dpcd_caps.branch_dev_name, branch_vendor_data)) {
++ DRM_INFO("Synaptics Cascaded MST hub\n");
++ return true;
++ }
++ }
++
++ return false;
++}
++
+ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnector)
+ {
+ struct dc_sink *dc_sink = aconnector->dc_sink;
+@@ -231,6 +246,10 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
+ needs_dsc_aux_workaround(aconnector->dc_link))
+ aconnector->dsc_aux = &aconnector->mst_port->dm_dp_aux.aux;
+
++ /* synaptics cascaded MST hub case */
++ if (!aconnector->dsc_aux && is_synaptics_cascaded_panamera(aconnector->dc_link, port))
++ aconnector->dsc_aux = port->mgr->aux;
++
+ if (!aconnector->dsc_aux)
+ return false;
+
+@@ -627,12 +646,25 @@ struct dsc_mst_fairness_params {
+ struct amdgpu_dm_connector *aconnector;
+ };
+
+-static int kbps_to_peak_pbn(int kbps)
++static uint16_t get_fec_overhead_multiplier(struct dc_link *dc_link)
++{
++ u8 link_coding_cap;
++ uint16_t fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B;
++
++ link_coding_cap = dc_link_dp_mst_decide_link_encoding_format(dc_link);
++ if (link_coding_cap == DP_128b_132b_ENCODING)
++ fec_overhead_multiplier_x1000 = PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B;
++
++ return fec_overhead_multiplier_x1000;
++}
++
++static int kbps_to_peak_pbn(int kbps, uint16_t fec_overhead_multiplier_x1000)
+ {
+ u64 peak_kbps = kbps;
+
+ peak_kbps *= 1006;
+- peak_kbps = div_u64(peak_kbps, 1000);
++ peak_kbps *= fec_overhead_multiplier_x1000;
++ peak_kbps = div_u64(peak_kbps, 1000 * 1000);
+ return (int) DIV64_U64_ROUND_UP(peak_kbps * 64, (54 * 8 * 1000));
+ }
+
+@@ -719,11 +751,12 @@ static int increase_dsc_bpp(struct drm_atomic_state *state,
+ int link_timeslots_used;
+ int fair_pbn_alloc;
+ int ret = 0;
++ uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
+
+ for (i = 0; i < count; i++) {
+ if (vars[i + k].dsc_enabled) {
+ initial_slack[i] =
+- kbps_to_peak_pbn(params[i].bw_range.max_kbps) - vars[i + k].pbn;
++ kbps_to_peak_pbn(params[i].bw_range.max_kbps, fec_overhead_multiplier_x1000) - vars[i + k].pbn;
+ bpp_increased[i] = false;
+ remaining_to_increase += 1;
+ } else {
+@@ -819,6 +852,7 @@ static int try_disable_dsc(struct drm_atomic_state *state,
+ int next_index;
+ int remaining_to_try = 0;
+ int ret;
++ uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
+
+ for (i = 0; i < count; i++) {
+ if (vars[i + k].dsc_enabled
+@@ -848,7 +882,7 @@ static int try_disable_dsc(struct drm_atomic_state *state,
+ if (next_index == -1)
+ break;
+
+- vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps);
++ vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+@@ -861,7 +895,7 @@ static int try_disable_dsc(struct drm_atomic_state *state,
+ vars[next_index].dsc_enabled = false;
+ vars[next_index].bpp_x16 = 0;
+ } else {
+- vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps);
++ vars[next_index].pbn = kbps_to_peak_pbn(params[next_index].bw_range.max_kbps, fec_overhead_multiplier_x1000);
+ ret = drm_dp_atomic_find_time_slots(state,
+ params[next_index].port->mgr,
+ params[next_index].port,
+@@ -890,6 +924,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
+ int count = 0;
+ int i, k, ret;
+ bool debugfs_overwrite = false;
++ uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link);
+
+ memset(params, 0, sizeof(params));
+
+@@ -951,7 +986,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
+ /* Try no compression */
+ for (i = 0; i < count; i++) {
+ vars[i + k].aconnector = params[i].aconnector;
+- vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
++ vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
+ vars[i + k].dsc_enabled = false;
+ vars[i + k].bpp_x16 = 0;
+ ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr, params[i].port,
+@@ -970,7 +1005,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
+ /* Try max compression */
+ for (i = 0; i < count; i++) {
+ if (params[i].compression_possible && params[i].clock_force_enable != DSC_CLK_FORCE_DISABLE) {
+- vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps);
++ vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.min_kbps, fec_overhead_multiplier_x1000);
+ vars[i + k].dsc_enabled = true;
+ vars[i + k].bpp_x16 = params[i].bw_range.min_target_bpp_x16;
+ ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
+@@ -978,7 +1013,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state,
+ if (ret < 0)
+ return ret;
+ } else {
+- vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps);
++ vars[i + k].pbn = kbps_to_peak_pbn(params[i].bw_range.stream_kbps, fec_overhead_multiplier_x1000);
+ vars[i + k].dsc_enabled = false;
+ vars[i + k].bpp_x16 = 0;
+ ret = drm_dp_atomic_find_time_slots(state, params[i].port->mgr,
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+index 97fd70df531bf..1e4ede1e57abd 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+@@ -34,6 +34,21 @@
+ #define SYNAPTICS_RC_OFFSET 0x4BC
+ #define SYNAPTICS_RC_DATA 0x4C0
+
++#define DP_BRANCH_VENDOR_SPECIFIC_START 0x50C
++
++/**
++ * Panamera MST Hub detection
++ * Offset DPCD 050Eh == 0x5A indicates cascaded MST hub case
++ * Check from beginning of branch device vendor specific field (050Ch)
++ */
++#define IS_SYNAPTICS_PANAMERA(branchDevName) (((int)branchDevName[4] & 0xF0) == 0x50 ? 1 : 0)
++#define BRANCH_HW_REVISION_PANAMERA_A2 0x10
++#define SYNAPTICS_CASCADED_HUB_ID 0x5A
++#define IS_SYNAPTICS_CASCADED_PANAMERA(devName, data) ((IS_SYNAPTICS_PANAMERA(devName) && ((int)data[2] == SYNAPTICS_CASCADED_HUB_ID)) ? 1 : 0)
++
++#define PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B 1031
++#define PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B 1000
++
+ struct amdgpu_display_manager;
+ struct amdgpu_dm_connector;
+
+diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+index 3fa2da1496398..fc594ea5bbc1d 100644
+--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
++++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c
+@@ -91,7 +91,15 @@ static void *etnaviv_gem_prime_vmap_impl(struct etnaviv_gem_object *etnaviv_obj)
+ static int etnaviv_gem_prime_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,
+ struct vm_area_struct *vma)
+ {
+- return dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0);
++ int ret;
++
++ ret = dma_buf_mmap(etnaviv_obj->base.dma_buf, vma, 0);
++ if (!ret) {
++ /* Drop the reference acquired by drm_gem_mmap_obj(). */
++ drm_gem_object_put(&etnaviv_obj->base);
++ }
++
++ return ret;
+ }
+
+ static const struct etnaviv_gem_ops etnaviv_gem_prime_ops = {
+diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c
+index 6bda4274eae92..c85757f55112b 100644
+--- a/drivers/gpu/drm/i915/display/intel_color.c
++++ b/drivers/gpu/drm/i915/display/intel_color.c
+@@ -499,6 +499,22 @@ static void icl_color_commit_noarm(const struct intel_crtc_state *crtc_state)
+ icl_load_csc_matrix(crtc_state);
+ }
+
++static void skl_color_commit_noarm(const struct intel_crtc_state *crtc_state)
++{
++ /*
++ * Possibly related to display WA #1184, SKL CSC loses the latched
++ * CSC coeff/offset register values if the CSC registers are disarmed
++ * between DC5 exit and PSR exit. This will cause the plane(s) to
++ * output all black (until CSC_MODE is rearmed and properly latched).
++ * Once PSR exit (and proper register latching) has occurred the
++ * danger is over. Thus when PSR is enabled the CSC coeff/offset
++ * register programming will be peformed from skl_color_commit_arm()
++ * which is called after PSR exit.
++ */
++ if (!crtc_state->has_psr)
++ ilk_load_csc_matrix(crtc_state);
++}
++
+ static void ilk_color_commit_noarm(const struct intel_crtc_state *crtc_state)
+ {
+ ilk_load_csc_matrix(crtc_state);
+@@ -541,6 +557,9 @@ static void skl_color_commit_arm(const struct intel_crtc_state *crtc_state)
+ enum pipe pipe = crtc->pipe;
+ u32 val = 0;
+
++ if (crtc_state->has_psr)
++ ilk_load_csc_matrix(crtc_state);
++
+ /*
+ * We don't (yet) allow userspace to control the pipe background color,
+ * so force it to black, but apply pipe gamma and CSC appropriately
+@@ -2171,7 +2190,7 @@ static const struct intel_color_funcs icl_color_funcs = {
+
+ static const struct intel_color_funcs glk_color_funcs = {
+ .color_check = glk_color_check,
+- .color_commit_noarm = ilk_color_commit_noarm,
++ .color_commit_noarm = skl_color_commit_noarm,
+ .color_commit_arm = skl_color_commit_arm,
+ .load_luts = glk_load_luts,
+ .read_luts = glk_read_luts,
+@@ -2179,7 +2198,7 @@ static const struct intel_color_funcs glk_color_funcs = {
+
+ static const struct intel_color_funcs skl_color_funcs = {
+ .color_check = ivb_color_check,
+- .color_commit_noarm = ilk_color_commit_noarm,
++ .color_commit_noarm = skl_color_commit_noarm,
+ .color_commit_arm = skl_color_commit_arm,
+ .load_luts = bdw_load_luts,
+ .read_luts = NULL,
+diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
+index e0d36edd1e3fb..3f3982ae9974b 100644
+--- a/drivers/gpu/drm/i915/display/intel_display.c
++++ b/drivers/gpu/drm/i915/display/intel_display.c
+@@ -7124,6 +7124,8 @@ static void intel_update_crtc(struct intel_atomic_state *state,
+
+ intel_fbc_update(state, crtc);
+
++ drm_WARN_ON(&i915->drm, !intel_display_power_is_enabled(i915, POWER_DOMAIN_DC_OFF));
++
+ if (!modeset &&
+ (new_crtc_state->uapi.color_mgmt_changed ||
+ new_crtc_state->update_pipe))
+@@ -7500,8 +7502,28 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
+ drm_atomic_helper_wait_for_dependencies(&state->base);
+ drm_dp_mst_atomic_wait_for_dependencies(&state->base);
+
+- if (state->modeset)
+- wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
++ /*
++ * During full modesets we write a lot of registers, wait
++ * for PLLs, etc. Doing that while DC states are enabled
++ * is not a good idea.
++ *
++ * During fastsets and other updates we also need to
++ * disable DC states due to the following scenario:
++ * 1. DC5 exit and PSR exit happen
++ * 2. Some or all _noarm() registers are written
++ * 3. Due to some long delay PSR is re-entered
++ * 4. DC5 entry -> DMC saves the already written new
++ * _noarm() registers and the old not yet written
++ * _arm() registers
++ * 5. DC5 exit -> DMC restores a mixture of old and
++ * new register values and arms the update
++ * 6. PSR exit -> hardware latches a mixture of old and
++ * new register values -> corrupted frame, or worse
++ * 7. New _arm() registers are finally written
++ * 8. Hardware finally latches a complete set of new
++ * register values, and subsequent frames will be OK again
++ */
++ wakeref = intel_display_power_get(dev_priv, POWER_DOMAIN_DC_OFF);
+
+ intel_atomic_prepare_plane_clear_colors(state);
+
+@@ -7640,8 +7662,8 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
+ * the culprit.
+ */
+ intel_uncore_arm_unclaimed_mmio_detection(&dev_priv->uncore);
+- intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET, wakeref);
+ }
++ intel_display_power_put(dev_priv, POWER_DOMAIN_DC_OFF, wakeref);
+ intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref);
+
+ /*
+diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c
+index ac587647e1f50..a3893aff38611 100644
+--- a/drivers/gpu/drm/i915/display/intel_dpt.c
++++ b/drivers/gpu/drm/i915/display/intel_dpt.c
+@@ -300,6 +300,7 @@ intel_dpt_create(struct intel_framebuffer *fb)
+ vm->pte_encode = gen8_ggtt_pte_encode;
+
+ dpt->obj = dpt_obj;
++ dpt->obj->is_dpt = true;
+
+ return &dpt->vm;
+ }
+@@ -308,5 +309,6 @@ void intel_dpt_destroy(struct i915_address_space *vm)
+ {
+ struct i915_dpt *dpt = i915_vm_to_dpt(vm);
+
++ dpt->obj->is_dpt = false;
+ i915_vm_put(&dpt->vm);
+ }
+diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c
+index e5af955b5600f..8d6dac32c8960 100644
+--- a/drivers/gpu/drm/i915/display/intel_tc.c
++++ b/drivers/gpu/drm/i915/display/intel_tc.c
+@@ -440,9 +440,9 @@ static bool icl_tc_phy_is_owned(struct intel_digital_port *dig_port)
+ PORT_TX_DFLEXDPCSSS(dig_port->tc_phy_fia));
+ if (val == 0xffffffff) {
+ drm_dbg_kms(&i915->drm,
+- "Port %s: PHY in TCCOLD, assume safe mode\n",
++ "Port %s: PHY in TCCOLD, assume not owned\n",
+ dig_port->tc_port_name);
+- return true;
++ return false;
+ }
+
+ return val & DP_PHY_MODE_STATUS_NOT_SAFE(dig_port->tc_phy_fia_idx);
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+index 8949fb0a944f6..3198b64ad7dbc 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_lmem.c
+@@ -127,7 +127,8 @@ i915_gem_object_create_lmem_from_data(struct drm_i915_private *i915,
+
+ memcpy(map, data, size);
+
+- i915_gem_object_unpin_map(obj);
++ i915_gem_object_flush_map(obj);
++ __i915_gem_object_release_map(obj);
+
+ return obj;
+ }
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
+index 1723af9b0f6a2..ea951e2f55b17 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
++++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
+@@ -319,7 +319,7 @@ i915_gem_object_never_mmap(const struct drm_i915_gem_object *obj)
+ static inline bool
+ i915_gem_object_is_framebuffer(const struct drm_i915_gem_object *obj)
+ {
+- return READ_ONCE(obj->frontbuffer);
++ return READ_ONCE(obj->frontbuffer) || obj->is_dpt;
+ }
+
+ static inline unsigned int
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+index ab4c2f90a5643..1d0d8ee9d707d 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
++++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h
+@@ -491,6 +491,9 @@ struct drm_i915_gem_object {
+ */
+ unsigned int cache_dirty:1;
+
++ /* @is_dpt: Object houses a display page table (DPT) */
++ unsigned int is_dpt:1;
++
+ /**
+ * @read_domains: Read memory domains.
+ *
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+index 41c93a18d5cb3..32a3c42ec45b1 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+@@ -356,7 +356,7 @@ static const struct dpu_caps sc8180x_dpu_caps = {
+ static const struct dpu_caps sm8250_dpu_caps = {
+ .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH,
+ .max_mixer_blendstages = 0xb,
+- .qseed_type = DPU_SSPP_SCALER_QSEED3LITE,
++ .qseed_type = DPU_SSPP_SCALER_QSEED4,
+ .smart_dma_rev = DPU_SSPP_SMART_DMA_V2, /* TODO: v2.5 */
+ .ubwc_version = DPU_HW_UBWC_VER_40,
+ .has_src_split = true,
+@@ -855,22 +855,22 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = {
+ };
+
+ static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 =
+- _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED3LITE);
++ _VIG_SBLK("0", 5, DPU_SSPP_SCALER_QSEED4);
+ static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 =
+- _VIG_SBLK("1", 6, DPU_SSPP_SCALER_QSEED3LITE);
++ _VIG_SBLK("1", 6, DPU_SSPP_SCALER_QSEED4);
+ static const struct dpu_sspp_sub_blks sm8250_vig_sblk_2 =
+- _VIG_SBLK("2", 7, DPU_SSPP_SCALER_QSEED3LITE);
++ _VIG_SBLK("2", 7, DPU_SSPP_SCALER_QSEED4);
+ static const struct dpu_sspp_sub_blks sm8250_vig_sblk_3 =
+- _VIG_SBLK("3", 8, DPU_SSPP_SCALER_QSEED3LITE);
++ _VIG_SBLK("3", 8, DPU_SSPP_SCALER_QSEED4);
+
+ static const struct dpu_sspp_cfg sm8250_sspp[] = {
+- SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SM8250_MASK,
++ SSPP_BLK("sspp_0", SSPP_VIG0, 0x4000, VIG_SC7180_MASK,
+ sm8250_vig_sblk_0, 0, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG0),
+- SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SM8250_MASK,
++ SSPP_BLK("sspp_1", SSPP_VIG1, 0x6000, VIG_SC7180_MASK,
+ sm8250_vig_sblk_1, 4, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG1),
+- SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SM8250_MASK,
++ SSPP_BLK("sspp_2", SSPP_VIG2, 0x8000, VIG_SC7180_MASK,
+ sm8250_vig_sblk_2, 8, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG2),
+- SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SM8250_MASK,
++ SSPP_BLK("sspp_3", SSPP_VIG3, 0xa000, VIG_SC7180_MASK,
+ sm8250_vig_sblk_3, 12, SSPP_TYPE_VIG, DPU_CLK_CTRL_VIG3),
+ SSPP_BLK("sspp_8", SSPP_DMA0, 0x24000, DMA_SDM845_MASK,
+ sdm845_dma_sblk_0, 1, SSPP_TYPE_DMA, DPU_CLK_CTRL_DMA0),
+@@ -1180,6 +1180,13 @@ static const struct dpu_pingpong_cfg sm8150_pp[] = {
+ -1),
+ };
+
++static const struct dpu_pingpong_cfg sc7280_pp[] = {
++ PP_BLK("pingpong_0", PINGPONG_0, 0x69000, 0, sc7280_pp_sblk, -1, -1),
++ PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1),
++ PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1),
++ PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1),
++};
++
+ static struct dpu_pingpong_cfg qcm2290_pp[] = {
+ PP_BLK("pingpong_0", PINGPONG_0, 0x70000, 0, sdm845_pp_sblk,
+ DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8),
+@@ -1203,13 +1210,6 @@ static const struct dpu_merge_3d_cfg sm8150_merge_3d[] = {
+ MERGE_3D_BLK("merge_3d_2", MERGE_3D_2, 0x83200),
+ };
+
+-static const struct dpu_pingpong_cfg sc7280_pp[] = {
+- PP_BLK("pingpong_0", PINGPONG_0, 0x59000, 0, sc7280_pp_sblk, -1, -1),
+- PP_BLK("pingpong_1", PINGPONG_1, 0x6a000, 0, sc7280_pp_sblk, -1, -1),
+- PP_BLK("pingpong_2", PINGPONG_2, 0x6b000, 0, sc7280_pp_sblk, -1, -1),
+- PP_BLK("pingpong_3", PINGPONG_3, 0x6c000, 0, sc7280_pp_sblk, -1, -1),
+-};
+-
+ /*************************************************************
+ * DSC sub blocks config
+ *************************************************************/
+diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
+index f060ac7376e69..cfeb24d40d378 100644
+--- a/drivers/idle/intel_idle.c
++++ b/drivers/idle/intel_idle.c
+@@ -168,7 +168,13 @@ static __cpuidle int intel_idle_irq(struct cpuidle_device *dev,
+
+ raw_local_irq_enable();
+ ret = __intel_idle(dev, drv, index);
+- raw_local_irq_disable();
++
++ /*
++ * The lockdep hardirqs state may be changed to 'on' with timer
++ * tick interrupt followed by __do_softirq(). Use local_irq_disable()
++ * to keep the hardirqs state correct.
++ */
++ local_irq_disable();
+
+ return ret;
+ }
+diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
+index 2959d80f7fdb6..cd36cf7165423 100644
+--- a/drivers/input/joystick/xpad.c
++++ b/drivers/input/joystick/xpad.c
+@@ -779,9 +779,6 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
+ input_report_key(dev, BTN_C, data[8]);
+ input_report_key(dev, BTN_Z, data[9]);
+
+- /* Profile button has a value of 0-3, so it is reported as an axis */
+- if (xpad->mapping & MAP_PROFILE_BUTTON)
+- input_report_abs(dev, ABS_PROFILE, data[34]);
+
+ input_sync(dev);
+ }
+@@ -1059,6 +1056,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
+ (__u16) le16_to_cpup((__le16 *)(data + 8)));
+ }
+
++ /* Profile button has a value of 0-3, so it is reported as an axis */
++ if (xpad->mapping & MAP_PROFILE_BUTTON)
++ input_report_abs(dev, ABS_PROFILE, data[34]);
++
+ /* paddle handling */
+ /* based on SDL's SDL_hidapi_xboxone.c */
+ if (xpad->mapping & MAP_PADDLES) {
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 4a6b33bbe7eaf..dd08ce97e7c90 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -852,8 +852,8 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
+ x = y = z = 0;
+
+ /* Divide 4 since trackpoint's speed is too fast */
+- input_report_rel(dev2, REL_X, (char)x / 4);
+- input_report_rel(dev2, REL_Y, -((char)y / 4));
++ input_report_rel(dev2, REL_X, (s8)x / 4);
++ input_report_rel(dev2, REL_Y, -((s8)y / 4));
+
+ psmouse_report_standard_buttons(dev2, packet[3]);
+
+@@ -1104,8 +1104,8 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
+ ((packet[3] & 0x20) << 1);
+ z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
+
+- input_report_rel(dev2, REL_X, (char)x);
+- input_report_rel(dev2, REL_Y, -((char)y));
++ input_report_rel(dev2, REL_X, (s8)x);
++ input_report_rel(dev2, REL_Y, -((s8)y));
+ input_report_abs(dev2, ABS_PRESSURE, z);
+
+ psmouse_report_standard_buttons(dev2, packet[1]);
+@@ -2294,20 +2294,20 @@ static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch)
+ if (reg < 0)
+ return reg;
+
+- x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
++ x_pitch = (s8)(reg << 4) >> 4; /* sign extend lower 4 bits */
+ x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
+
+- y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
++ y_pitch = (s8)reg >> 4; /* sign extend upper 4 bits */
+ y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
+
+ reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
+ if (reg < 0)
+ return reg;
+
+- x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
++ x_electrode = (s8)(reg << 4) >> 4; /* sign extend lower 4 bits */
+ x_electrode = 17 + x_electrode;
+
+- y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
++ y_electrode = (s8)reg >> 4; /* sign extend upper 4 bits */
+ y_electrode = 13 + y_electrode;
+
+ x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
+diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
+index 6fd5fff0cbfff..c74b99077d16a 100644
+--- a/drivers/input/mouse/focaltech.c
++++ b/drivers/input/mouse/focaltech.c
+@@ -202,8 +202,8 @@ static void focaltech_process_rel_packet(struct psmouse *psmouse,
+ state->pressed = packet[0] >> 7;
+ finger1 = ((packet[0] >> 4) & 0x7) - 1;
+ if (finger1 < FOC_MAX_FINGERS) {
+- state->fingers[finger1].x += (char)packet[1];
+- state->fingers[finger1].y += (char)packet[2];
++ state->fingers[finger1].x += (s8)packet[1];
++ state->fingers[finger1].y += (s8)packet[2];
+ } else {
+ psmouse_err(psmouse, "First finger in rel packet invalid: %d\n",
+ finger1);
+@@ -218,8 +218,8 @@ static void focaltech_process_rel_packet(struct psmouse *psmouse,
+ */
+ finger2 = ((packet[3] >> 4) & 0x7) - 1;
+ if (finger2 < FOC_MAX_FINGERS) {
+- state->fingers[finger2].x += (char)packet[4];
+- state->fingers[finger2].y += (char)packet[5];
++ state->fingers[finger2].x += (s8)packet[4];
++ state->fingers[finger2].y += (s8)packet[5];
+ }
+ }
+
+diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
+index efc61736099b9..028e45bd050bf 100644
+--- a/drivers/input/serio/i8042-acpipnpio.h
++++ b/drivers/input/serio/i8042-acpipnpio.h
+@@ -610,6 +610,14 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
+ },
+ .driver_data = (void *)(SERIO_QUIRK_NOMUX)
+ },
++ {
++ /* Fujitsu Lifebook A574/H */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
++ DMI_MATCH(DMI_PRODUCT_NAME, "FMVA0501PZ"),
++ },
++ .driver_data = (void *)(SERIO_QUIRK_NOMUX)
++ },
+ {
+ /* Gigabyte M912 */
+ .matches = {
+@@ -1116,6 +1124,20 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
+ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ },
++ {
++ /*
++ * Setting SERIO_QUIRK_NOMUX or SERIO_QUIRK_RESET_ALWAYS makes
++ * the keyboard very laggy for ~5 seconds after boot and
++ * sometimes also after resume.
++ * However both are required for the keyboard to not fail
++ * completely sometimes after boot or resume.
++ */
++ .matches = {
++ DMI_MATCH(DMI_BOARD_NAME, "N150CU"),
++ },
++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
++ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
+@@ -1123,6 +1145,20 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
+ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
+ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ },
++ {
++ /*
++ * Setting SERIO_QUIRK_NOMUX or SERIO_QUIRK_RESET_ALWAYS makes
++ * the keyboard very laggy for ~5 seconds after boot and
++ * sometimes also after resume.
++ * However both are required for the keyboard to not fail
++ * completely sometimes after boot or resume.
++ */
++ .matches = {
++ DMI_MATCH(DMI_BOARD_NAME, "NHxxRZQ"),
++ },
++ .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
++ SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
++ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
+diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
+index c281e49826c23..25e575183dd18 100644
+--- a/drivers/input/touchscreen/goodix.c
++++ b/drivers/input/touchscreen/goodix.c
+@@ -124,10 +124,18 @@ static const unsigned long goodix_irq_flags[] = {
+ static const struct dmi_system_id nine_bytes_report[] = {
+ #if defined(CONFIG_DMI) && defined(CONFIG_X86)
+ {
+- .ident = "Lenovo YogaBook",
+- /* YB1-X91L/F and YB1-X90L/F */
++ /* Lenovo Yoga Book X90F / X90L */
+ .matches = {
+- DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9")
++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
++ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
++ }
++ },
++ {
++ /* Lenovo Yoga Book X91F / X91L */
++ .matches = {
++ /* Non exact match to match F + L versions */
++ DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
+ }
+ },
+ #endif
+diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
+index bc94059a5b870..f800989ea0462 100644
+--- a/drivers/iommu/intel/dmar.c
++++ b/drivers/iommu/intel/dmar.c
+@@ -1057,7 +1057,8 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
+ }
+
+ err = -EINVAL;
+- if (cap_sagaw(iommu->cap) == 0) {
++ if (!cap_sagaw(iommu->cap) &&
++ (!ecap_smts(iommu->ecap) || ecap_slts(iommu->ecap))) {
+ pr_info("%s: No supported address widths. Not attempting DMA translation.\n",
+ iommu->name);
+ drhd->ignored = 1;
+diff --git a/drivers/md/dm.c b/drivers/md/dm.c
+index 89bf28ed874c2..38d8aa21ef7ac 100644
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -1522,6 +1522,8 @@ static int __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti,
+ ret = 1;
+ break;
+ default:
++ if (len)
++ setup_split_accounting(ci, *len);
+ /* dm_accept_partial_bio() is not supported with shared tio->len_ptr */
+ alloc_multiple_bios(&blist, ci, ti, num_bios);
+ while ((clone = bio_list_pop(&blist))) {
+diff --git a/drivers/md/md.c b/drivers/md/md.c
+index 0368b3c51c7f7..d5c362b1602b6 100644
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -3152,6 +3152,9 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
+ err = kstrtouint(buf, 10, (unsigned int *)&slot);
+ if (err < 0)
+ return err;
++ if (slot < 0)
++ /* overflow */
++ return -ENOSPC;
+ }
+ if (rdev->mddev->pers && slot == -1) {
+ /* Setting 'slot' on an active array requires also
+diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c
+index 8afdca731b874..6b487ffe2f2dc 100644
+--- a/drivers/mtd/nand/ecc-mxic.c
++++ b/drivers/mtd/nand/ecc-mxic.c
+@@ -429,6 +429,7 @@ static int mxic_ecc_data_xfer_wait_for_completion(struct mxic_ecc_engine *mxic)
+ mxic_ecc_enable_int(mxic);
+ ret = wait_for_completion_timeout(&mxic->complete,
+ msecs_to_jiffies(1000));
++ ret = ret ? 0 : -ETIMEDOUT;
+ mxic_ecc_disable_int(mxic);
+ } else {
+ ret = readl_poll_timeout(mxic->regs + INTRPT_STS, val,
+diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c
+index 5ee01231ac4cd..a28574c009003 100644
+--- a/drivers/mtd/nand/raw/meson_nand.c
++++ b/drivers/mtd/nand/raw/meson_nand.c
+@@ -176,6 +176,7 @@ struct meson_nfc {
+
+ dma_addr_t daddr;
+ dma_addr_t iaddr;
++ u32 info_bytes;
+
+ unsigned long assigned_cs;
+ };
+@@ -503,6 +504,7 @@ static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, void *databuf,
+ nfc->daddr, datalen, dir);
+ return ret;
+ }
++ nfc->info_bytes = infolen;
+ cmd = GENCMDIADDRL(NFC_CMD_AIL, nfc->iaddr);
+ writel(cmd, nfc->reg_base + NFC_REG_CMD);
+
+@@ -520,8 +522,10 @@ static void meson_nfc_dma_buffer_release(struct nand_chip *nand,
+ struct meson_nfc *nfc = nand_get_controller_data(nand);
+
+ dma_unmap_single(nfc->dev, nfc->daddr, datalen, dir);
+- if (infolen)
++ if (infolen) {
+ dma_unmap_single(nfc->dev, nfc->iaddr, infolen, dir);
++ nfc->info_bytes = 0;
++ }
+ }
+
+ static int meson_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len)
+@@ -710,6 +714,8 @@ static void meson_nfc_check_ecc_pages_valid(struct meson_nfc *nfc,
+ usleep_range(10, 15);
+ /* info is updated by nfc dma engine*/
+ smp_rmb();
++ dma_sync_single_for_cpu(nfc->dev, nfc->iaddr, nfc->info_bytes,
++ DMA_FROM_DEVICE);
+ ret = *info & ECC_COMPLETE;
+ } while (!ret);
+ }
+@@ -991,7 +997,7 @@ static const struct mtd_ooblayout_ops meson_ooblayout_ops = {
+
+ static int meson_nfc_clk_init(struct meson_nfc *nfc)
+ {
+- struct clk_parent_data nfc_divider_parent_data[1];
++ struct clk_parent_data nfc_divider_parent_data[1] = {0};
+ struct clk_init_data init = {0};
+ int ret;
+
+diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
+index bd3b133e7085b..22250ae222b5b 100644
+--- a/drivers/net/dsa/microchip/ksz8795.c
++++ b/drivers/net/dsa/microchip/ksz8795.c
+@@ -907,15 +907,14 @@ int ksz8_fdb_dump(struct ksz_device *dev, int port,
+ u16 entries = 0;
+ u8 timestamp = 0;
+ u8 fid;
+- u8 member;
+- struct alu_struct alu;
++ u8 src_port;
++ u8 mac[ETH_ALEN];
+
+ do {
+- alu.is_static = false;
+- ret = ksz8_r_dyn_mac_table(dev, i, alu.mac, &fid, &member,
++ ret = ksz8_r_dyn_mac_table(dev, i, mac, &fid, &src_port,
+ &timestamp, &entries);
+- if (!ret && (member & BIT(port))) {
+- ret = cb(alu.mac, alu.fid, alu.is_static, data);
++ if (!ret && port == src_port) {
++ ret = cb(mac, fid, false, data);
+ if (ret)
+ break;
+ }
+diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c
+index ddb40838181ef..ed77ac2228951 100644
+--- a/drivers/net/dsa/microchip/ksz8863_smi.c
++++ b/drivers/net/dsa/microchip/ksz8863_smi.c
+@@ -82,22 +82,16 @@ static const struct regmap_bus regmap_smi[] = {
+ {
+ .read = ksz8863_mdio_read,
+ .write = ksz8863_mdio_write,
+- .max_raw_read = 1,
+- .max_raw_write = 1,
+ },
+ {
+ .read = ksz8863_mdio_read,
+ .write = ksz8863_mdio_write,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+- .max_raw_read = 2,
+- .max_raw_write = 2,
+ },
+ {
+ .read = ksz8863_mdio_read,
+ .write = ksz8863_mdio_write,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+- .max_raw_read = 4,
+- .max_raw_write = 4,
+ }
+ };
+
+@@ -108,7 +102,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {
+ .pad_bits = 24,
+ .val_bits = 8,
+ .cache_type = REGCACHE_NONE,
+- .use_single_read = 1,
+ .lock = ksz_regmap_lock,
+ .unlock = ksz_regmap_unlock,
+ },
+@@ -118,7 +111,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {
+ .pad_bits = 24,
+ .val_bits = 16,
+ .cache_type = REGCACHE_NONE,
+- .use_single_read = 1,
+ .lock = ksz_regmap_lock,
+ .unlock = ksz_regmap_unlock,
+ },
+@@ -128,7 +120,6 @@ static const struct regmap_config ksz8863_regmap_config[] = {
+ .pad_bits = 24,
+ .val_bits = 32,
+ .cache_type = REGCACHE_NONE,
+- .use_single_read = 1,
+ .lock = ksz_regmap_lock,
+ .unlock = ksz_regmap_unlock,
+ }
+diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
+index 07f6776bba12b..3d59298eaa5cf 100644
+--- a/drivers/net/dsa/microchip/ksz_common.c
++++ b/drivers/net/dsa/microchip/ksz_common.c
+@@ -357,13 +357,13 @@ static const u32 ksz8863_masks[] = {
+ [VLAN_TABLE_VALID] = BIT(19),
+ [STATIC_MAC_TABLE_VALID] = BIT(19),
+ [STATIC_MAC_TABLE_USE_FID] = BIT(21),
+- [STATIC_MAC_TABLE_FID] = GENMASK(29, 26),
++ [STATIC_MAC_TABLE_FID] = GENMASK(25, 22),
+ [STATIC_MAC_TABLE_OVERRIDE] = BIT(20),
+ [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(18, 16),
+- [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(5, 0),
+- [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(7),
++ [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(1, 0),
++ [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(2),
+ [DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7),
+- [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 28),
++ [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 24),
+ [DYNAMIC_MAC_TABLE_FID] = GENMASK(19, 16),
+ [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(21, 20),
+ [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(23, 22),
+@@ -373,10 +373,10 @@ static u8 ksz8863_shifts[] = {
+ [VLAN_TABLE_MEMBERSHIP_S] = 16,
+ [STATIC_MAC_FWD_PORTS] = 16,
+ [STATIC_MAC_FID] = 22,
+- [DYNAMIC_MAC_ENTRIES_H] = 3,
++ [DYNAMIC_MAC_ENTRIES_H] = 8,
+ [DYNAMIC_MAC_ENTRIES] = 24,
+ [DYNAMIC_MAC_FID] = 16,
+- [DYNAMIC_MAC_TIMESTAMP] = 24,
++ [DYNAMIC_MAC_TIMESTAMP] = 22,
+ [DYNAMIC_MAC_SRC_PORT] = 20,
+ };
+
+diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
+index c8eca2b6f9594..49bf358b9c4fa 100644
+--- a/drivers/net/dsa/mv88e6xxx/Makefile
++++ b/drivers/net/dsa/mv88e6xxx/Makefile
+@@ -15,3 +15,7 @@ mv88e6xxx-objs += port_hidden.o
+ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += ptp.o
+ mv88e6xxx-objs += serdes.o
+ mv88e6xxx-objs += smi.o
++mv88e6xxx-objs += trace.o
++
++# for tracing framework to find trace.h
++CFLAGS_trace.o := -I$(src)
+diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
+index 3a6db36574ad7..8cf27e2654fcf 100644
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -3354,9 +3354,14 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
+ * If this is the upstream port for this switch, enable
+ * forwarding of unknown unicasts and multicasts.
+ */
+- reg = MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP |
+- MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
++ reg = MV88E6185_PORT_CTL0_USE_TAG | MV88E6185_PORT_CTL0_USE_IP |
+ MV88E6XXX_PORT_CTL0_STATE_FORWARDING;
++ /* Forward any IPv4 IGMP or IPv6 MLD frames received
++ * by a USER port to the CPU port to allow snooping.
++ */
++ if (dsa_is_user_port(ds, port))
++ reg |= MV88E6XXX_PORT_CTL0_IGMP_MLD_SNOOP;
++
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg);
+ if (err)
+ return err;
+diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
+index 40bd67a5c8e93..7c513a03789cf 100644
+--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
++++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
+@@ -12,6 +12,7 @@
+
+ #include "chip.h"
+ #include "global1.h"
++#include "trace.h"
+
+ /* Offset 0x01: ATU FID Register */
+
+@@ -114,6 +115,19 @@ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
+ return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
+ }
+
++static int mv88e6xxx_g1_read_atu_violation(struct mv88e6xxx_chip *chip)
++{
++ int err;
++
++ err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
++ MV88E6XXX_G1_ATU_OP_BUSY |
++ MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
++ if (err)
++ return err;
++
++ return mv88e6xxx_g1_atu_op_wait(chip);
++}
++
+ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
+ {
+ u16 val;
+@@ -159,6 +173,41 @@ int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid)
+ return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB);
+ }
+
++static int mv88e6xxx_g1_atu_fid_read(struct mv88e6xxx_chip *chip, u16 *fid)
++{
++ u16 val = 0, upper = 0, op = 0;
++ int err = -EOPNOTSUPP;
++
++ if (mv88e6xxx_num_databases(chip) > 256) {
++ err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &val);
++ val &= 0xfff;
++ if (err)
++ return err;
++ } else {
++ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &op);
++ if (err)
++ return err;
++ if (mv88e6xxx_num_databases(chip) > 64) {
++ /* ATU DBNum[7:4] are located in ATU Control 15:12 */
++ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL,
++ &upper);
++ if (err)
++ return err;
++
++ upper = (upper >> 8) & 0x00f0;
++ } else if (mv88e6xxx_num_databases(chip) > 16) {
++ /* ATU DBNum[5:4] are located in ATU Operation 9:8 */
++ upper = (op >> 4) & 0x30;
++ }
++
++ /* ATU DBNum[3:0] are located in ATU Operation 3:0 */
++ val = (op & 0xf) | upper;
++ }
++ *fid = val;
++
++ return err;
++}
++
+ /* Offset 0x0C: ATU Data Register */
+
+ static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
+@@ -353,14 +402,12 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
+ {
+ struct mv88e6xxx_chip *chip = dev_id;
+ struct mv88e6xxx_atu_entry entry;
+- int spid;
+- int err;
+- u16 val;
++ int err, spid;
++ u16 val, fid;
+
+ mv88e6xxx_reg_lock(chip);
+
+- err = mv88e6xxx_g1_atu_op(chip, 0,
+- MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
++ err = mv88e6xxx_g1_read_atu_violation(chip);
+ if (err)
+ goto out;
+
+@@ -368,6 +415,10 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
+ if (err)
+ goto out;
+
++ err = mv88e6xxx_g1_atu_fid_read(chip, &fid);
++ if (err)
++ goto out;
++
+ err = mv88e6xxx_g1_atu_data_read(chip, &entry);
+ if (err)
+ goto out;
+@@ -385,23 +436,23 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
+ }
+
+ if (val & MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION) {
+- dev_err_ratelimited(chip->dev,
+- "ATU member violation for %pM portvec %x spid %d\n",
+- entry.mac, entry.portvec, spid);
++ trace_mv88e6xxx_atu_member_violation(chip->dev, spid,
++ entry.portvec, entry.mac,
++ fid);
+ chip->ports[spid].atu_member_violation++;
+ }
+
+ if (val & MV88E6XXX_G1_ATU_OP_MISS_VIOLATION) {
+- dev_err_ratelimited(chip->dev,
+- "ATU miss violation for %pM portvec %x spid %d\n",
+- entry.mac, entry.portvec, spid);
++ trace_mv88e6xxx_atu_miss_violation(chip->dev, spid,
++ entry.portvec, entry.mac,
++ fid);
+ chip->ports[spid].atu_miss_violation++;
+ }
+
+ if (val & MV88E6XXX_G1_ATU_OP_FULL_VIOLATION) {
+- dev_err_ratelimited(chip->dev,
+- "ATU full violation for %pM portvec %x spid %d\n",
+- entry.mac, entry.portvec, spid);
++ trace_mv88e6xxx_atu_full_violation(chip->dev, spid,
++ entry.portvec, entry.mac,
++ fid);
+ chip->ports[spid].atu_full_violation++;
+ }
+ mv88e6xxx_reg_unlock(chip);
+diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
+index 38e18f5811bfb..bcfb4a812055c 100644
+--- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c
++++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
+@@ -13,6 +13,7 @@
+
+ #include "chip.h"
+ #include "global1.h"
++#include "trace.h"
+
+ /* Offset 0x02: VTU FID Register */
+
+@@ -628,14 +629,12 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id)
+ spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK;
+
+ if (val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION) {
+- dev_err_ratelimited(chip->dev, "VTU member violation for vid %d, source port %d\n",
+- vid, spid);
++ trace_mv88e6xxx_vtu_member_violation(chip->dev, spid, vid);
+ chip->ports[spid].vtu_member_violation++;
+ }
+
+ if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) {
+- dev_dbg_ratelimited(chip->dev, "VTU miss violation for vid %d, source port %d\n",
+- vid, spid);
++ trace_mv88e6xxx_vtu_miss_violation(chip->dev, spid, vid);
+ chip->ports[spid].vtu_miss_violation++;
+ }
+
+diff --git a/drivers/net/dsa/mv88e6xxx/trace.c b/drivers/net/dsa/mv88e6xxx/trace.c
+new file mode 100644
+index 0000000000000..7833cb50ca5d7
+--- /dev/null
++++ b/drivers/net/dsa/mv88e6xxx/trace.c
+@@ -0,0 +1,6 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/* Copyright 2022 NXP
++ */
++
++#define CREATE_TRACE_POINTS
++#include "trace.h"
+diff --git a/drivers/net/dsa/mv88e6xxx/trace.h b/drivers/net/dsa/mv88e6xxx/trace.h
+new file mode 100644
+index 0000000000000..f59ca04768e79
+--- /dev/null
++++ b/drivers/net/dsa/mv88e6xxx/trace.h
+@@ -0,0 +1,96 @@
++/* SPDX-License-Identifier: GPL-2.0-or-later */
++/* Copyright 2022 NXP
++ */
++
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM mv88e6xxx
++
++#if !defined(_MV88E6XXX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _MV88E6XXX_TRACE_H
++
++#include <linux/device.h>
++#include <linux/if_ether.h>
++#include <linux/tracepoint.h>
++
++DECLARE_EVENT_CLASS(mv88e6xxx_atu_violation,
++
++ TP_PROTO(const struct device *dev, int spid, u16 portvec,
++ const unsigned char *addr, u16 fid),
++
++ TP_ARGS(dev, spid, portvec, addr, fid),
++
++ TP_STRUCT__entry(
++ __string(name, dev_name(dev))
++ __field(int, spid)
++ __field(u16, portvec)
++ __array(unsigned char, addr, ETH_ALEN)
++ __field(u16, fid)
++ ),
++
++ TP_fast_assign(
++ __assign_str(name, dev_name(dev));
++ __entry->spid = spid;
++ __entry->portvec = portvec;
++ memcpy(__entry->addr, addr, ETH_ALEN);
++ __entry->fid = fid;
++ ),
++
++ TP_printk("dev %s spid %d portvec 0x%x addr %pM fid %u",
++ __get_str(name), __entry->spid, __entry->portvec,
++ __entry->addr, __entry->fid)
++);
++
++DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_member_violation,
++ TP_PROTO(const struct device *dev, int spid, u16 portvec,
++ const unsigned char *addr, u16 fid),
++ TP_ARGS(dev, spid, portvec, addr, fid));
++
++DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_miss_violation,
++ TP_PROTO(const struct device *dev, int spid, u16 portvec,
++ const unsigned char *addr, u16 fid),
++ TP_ARGS(dev, spid, portvec, addr, fid));
++
++DEFINE_EVENT(mv88e6xxx_atu_violation, mv88e6xxx_atu_full_violation,
++ TP_PROTO(const struct device *dev, int spid, u16 portvec,
++ const unsigned char *addr, u16 fid),
++ TP_ARGS(dev, spid, portvec, addr, fid));
++
++DECLARE_EVENT_CLASS(mv88e6xxx_vtu_violation,
++
++ TP_PROTO(const struct device *dev, int spid, u16 vid),
++
++ TP_ARGS(dev, spid, vid),
++
++ TP_STRUCT__entry(
++ __string(name, dev_name(dev))
++ __field(int, spid)
++ __field(u16, vid)
++ ),
++
++ TP_fast_assign(
++ __assign_str(name, dev_name(dev));
++ __entry->spid = spid;
++ __entry->vid = vid;
++ ),
++
++ TP_printk("dev %s spid %d vid %u",
++ __get_str(name), __entry->spid, __entry->vid)
++);
++
++DEFINE_EVENT(mv88e6xxx_vtu_violation, mv88e6xxx_vtu_member_violation,
++ TP_PROTO(const struct device *dev, int spid, u16 vid),
++ TP_ARGS(dev, spid, vid));
++
++DEFINE_EVENT(mv88e6xxx_vtu_violation, mv88e6xxx_vtu_miss_violation,
++ TP_PROTO(const struct device *dev, int spid, u16 vid),
++ TP_ARGS(dev, spid, vid));
++
++#endif /* _MV88E6XXX_TRACE_H */
++
++/* We don't want to use include/trace/events */
++#undef TRACE_INCLUDE_PATH
++#define TRACE_INCLUDE_PATH .
++#undef TRACE_INCLUDE_FILE
++#define TRACE_INCLUDE_FILE trace
++/* This part must be outside protection */
++#include <trace/define_trace.h>
+diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c
+index 3e54fac5f9027..5a8fe707ca25e 100644
+--- a/drivers/net/dsa/realtek/realtek-mdio.c
++++ b/drivers/net/dsa/realtek/realtek-mdio.c
+@@ -21,6 +21,7 @@
+
+ #include <linux/module.h>
+ #include <linux/of_device.h>
++#include <linux/overflow.h>
+ #include <linux/regmap.h>
+
+ #include "realtek.h"
+@@ -152,7 +153,9 @@ static int realtek_mdio_probe(struct mdio_device *mdiodev)
+ if (!var)
+ return -EINVAL;
+
+- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
++ priv = devm_kzalloc(&mdiodev->dev,
++ size_add(sizeof(*priv), var->chip_data_sz),
++ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 251b102d2792b..c6e36603bd2db 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -175,12 +175,12 @@ static const struct pci_device_id bnxt_pci_tbl[] = {
+ { PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 },
+ { PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 },
+ { PCI_VDEVICE(BROADCOM, 0x1752), .driver_data = BCM57502 },
+- { PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57508_NPAR },
++ { PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57502_NPAR },
+ { PCI_VDEVICE(BROADCOM, 0x1801), .driver_data = BCM57504_NPAR },
+- { PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57502_NPAR },
+- { PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57508_NPAR },
++ { PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57508_NPAR },
++ { PCI_VDEVICE(BROADCOM, 0x1803), .driver_data = BCM57502_NPAR },
+ { PCI_VDEVICE(BROADCOM, 0x1804), .driver_data = BCM57504_NPAR },
+- { PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57502_NPAR },
++ { PCI_VDEVICE(BROADCOM, 0x1805), .driver_data = BCM57508_NPAR },
+ { PCI_VDEVICE(BROADCOM, 0xd802), .driver_data = BCM58802 },
+ { PCI_VDEVICE(BROADCOM, 0xd804), .driver_data = BCM58804 },
+ #ifdef CONFIG_BNXT_SRIOV
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+index 02741d499bf4a..1d2588c92977e 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+@@ -1225,6 +1225,7 @@ struct bnxt_link_info {
+ #define BNXT_LINK_SPEED_40GB PORT_PHY_QCFG_RESP_LINK_SPEED_40GB
+ #define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB
+ #define BNXT_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB
++#define BNXT_LINK_SPEED_200GB PORT_PHY_QCFG_RESP_LINK_SPEED_200GB
+ u16 support_speeds;
+ u16 support_pam4_speeds;
+ u16 auto_link_speeds; /* fw adv setting */
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+index 703fc163235f9..01b973bc509f5 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+@@ -1712,6 +1712,8 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
+ return SPEED_50000;
+ case BNXT_LINK_SPEED_100GB:
+ return SPEED_100000;
++ case BNXT_LINK_SPEED_200GB:
++ return SPEED_200000;
+ default:
+ return SPEED_UNKNOWN;
+ }
+@@ -3634,6 +3636,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
+ bnxt_ulp_stop(bp);
+ rc = bnxt_close_nic(bp, true, false);
+ if (rc) {
++ etest->flags |= ETH_TEST_FL_FAILED;
+ bnxt_ulp_start(bp, rc);
+ return;
+ }
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c
+index ef4d3762bf371..ca229b0efeb65 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_diag.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_diag.c
+@@ -44,7 +44,7 @@ static i40e_status i40e_diag_reg_pattern_test(struct i40e_hw *hw,
+ return 0;
+ }
+
+-struct i40e_diag_reg_test_info i40e_reg_list[] = {
++const struct i40e_diag_reg_test_info i40e_reg_list[] = {
+ /* offset mask elements stride */
+ {I40E_QTX_CTL(0), 0x0000FFBF, 1,
+ I40E_QTX_CTL(1) - I40E_QTX_CTL(0)},
+@@ -78,27 +78,28 @@ i40e_status i40e_diag_reg_test(struct i40e_hw *hw)
+ {
+ i40e_status ret_code = 0;
+ u32 reg, mask;
++ u32 elements;
+ u32 i, j;
+
+ for (i = 0; i40e_reg_list[i].offset != 0 &&
+ !ret_code; i++) {
+
++ elements = i40e_reg_list[i].elements;
+ /* set actual reg range for dynamically allocated resources */
+ if (i40e_reg_list[i].offset == I40E_QTX_CTL(0) &&
+ hw->func_caps.num_tx_qp != 0)
+- i40e_reg_list[i].elements = hw->func_caps.num_tx_qp;
++ elements = hw->func_caps.num_tx_qp;
+ if ((i40e_reg_list[i].offset == I40E_PFINT_ITRN(0, 0) ||
+ i40e_reg_list[i].offset == I40E_PFINT_ITRN(1, 0) ||
+ i40e_reg_list[i].offset == I40E_PFINT_ITRN(2, 0) ||
+ i40e_reg_list[i].offset == I40E_QINT_TQCTL(0) ||
+ i40e_reg_list[i].offset == I40E_QINT_RQCTL(0)) &&
+ hw->func_caps.num_msix_vectors != 0)
+- i40e_reg_list[i].elements =
+- hw->func_caps.num_msix_vectors - 1;
++ elements = hw->func_caps.num_msix_vectors - 1;
+
+ /* test register access */
+ mask = i40e_reg_list[i].mask;
+- for (j = 0; j < i40e_reg_list[i].elements && !ret_code; j++) {
++ for (j = 0; j < elements && !ret_code; j++) {
+ reg = i40e_reg_list[i].offset +
+ (j * i40e_reg_list[i].stride);
+ ret_code = i40e_diag_reg_pattern_test(hw, reg, mask);
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.h b/drivers/net/ethernet/intel/i40e/i40e_diag.h
+index c3340f320a18c..1db7c6d572311 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_diag.h
++++ b/drivers/net/ethernet/intel/i40e/i40e_diag.h
+@@ -20,7 +20,7 @@ struct i40e_diag_reg_test_info {
+ u32 stride; /* bytes between each element */
+ };
+
+-extern struct i40e_diag_reg_test_info i40e_reg_list[];
++extern const struct i40e_diag_reg_test_info i40e_reg_list[];
+
+ i40e_status i40e_diag_reg_test(struct i40e_hw *hw);
+ i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw);
+diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
+index 118595763bba3..2c62c1763ee0d 100644
+--- a/drivers/net/ethernet/intel/ice/ice_sched.c
++++ b/drivers/net/ethernet/intel/ice/ice_sched.c
+@@ -2756,7 +2756,7 @@ static int
+ ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
+ u16 vsi_handle, unsigned long *tc_bitmap)
+ {
+- struct ice_sched_agg_vsi_info *agg_vsi_info, *old_agg_vsi_info = NULL;
++ struct ice_sched_agg_vsi_info *agg_vsi_info, *iter, *old_agg_vsi_info = NULL;
+ struct ice_sched_agg_info *agg_info, *old_agg_info;
+ struct ice_hw *hw = pi->hw;
+ int status = 0;
+@@ -2774,11 +2774,13 @@ ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id,
+ if (old_agg_info && old_agg_info != agg_info) {
+ struct ice_sched_agg_vsi_info *vtmp;
+
+- list_for_each_entry_safe(old_agg_vsi_info, vtmp,
++ list_for_each_entry_safe(iter, vtmp,
+ &old_agg_info->agg_vsi_list,
+ list_entry)
+- if (old_agg_vsi_info->vsi_handle == vsi_handle)
++ if (iter->vsi_handle == vsi_handle) {
++ old_agg_vsi_info = iter;
+ break;
++ }
+ }
+
+ /* check if entry already exist */
+diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
+index 61f844d225123..46b36851af460 100644
+--- a/drivers/net/ethernet/intel/ice/ice_switch.c
++++ b/drivers/net/ethernet/intel/ice/ice_switch.c
+@@ -1780,18 +1780,36 @@ ice_update_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx,
+ int
+ ice_cfg_rdma_fltr(struct ice_hw *hw, u16 vsi_handle, bool enable)
+ {
+- struct ice_vsi_ctx *ctx;
++ struct ice_vsi_ctx *ctx, *cached_ctx;
++ int status;
++
++ cached_ctx = ice_get_vsi_ctx(hw, vsi_handle);
++ if (!cached_ctx)
++ return -ENOENT;
+
+- ctx = ice_get_vsi_ctx(hw, vsi_handle);
++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+- return -EIO;
++ return -ENOMEM;
++
++ ctx->info.q_opt_rss = cached_ctx->info.q_opt_rss;
++ ctx->info.q_opt_tc = cached_ctx->info.q_opt_tc;
++ ctx->info.q_opt_flags = cached_ctx->info.q_opt_flags;
++
++ ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
+
+ if (enable)
+ ctx->info.q_opt_flags |= ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
+ else
+ ctx->info.q_opt_flags &= ~ICE_AQ_VSI_Q_OPT_PE_FLTR_EN;
+
+- return ice_update_vsi(hw, vsi_handle, ctx, NULL);
++ status = ice_update_vsi(hw, vsi_handle, ctx, NULL);
++ if (!status) {
++ cached_ctx->info.q_opt_flags = ctx->info.q_opt_flags;
++ cached_ctx->info.valid_sections |= ctx->info.valid_sections;
++ }
++
++ kfree(ctx);
++ return status;
+ }
+
+ /**
+diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
+index c6a58343d81d8..a2645ff3100e4 100644
+--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
++++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
+@@ -541,6 +541,72 @@ static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf)
+ }
+ }
+
++/**
++ * ice_vc_fdir_has_prof_conflict
++ * @vf: pointer to the VF structure
++ * @conf: FDIR configuration for each filter
++ *
++ * Check if @conf has conflicting profile with existing profiles
++ *
++ * Return: true on success, and false on error.
++ */
++static bool
++ice_vc_fdir_has_prof_conflict(struct ice_vf *vf,
++ struct virtchnl_fdir_fltr_conf *conf)
++{
++ struct ice_fdir_fltr *desc;
++
++ list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
++ struct virtchnl_fdir_fltr_conf *existing_conf;
++ enum ice_fltr_ptype flow_type_a, flow_type_b;
++ struct ice_fdir_fltr *a, *b;
++
++ existing_conf = to_fltr_conf_from_desc(desc);
++ a = &existing_conf->input;
++ b = &conf->input;
++ flow_type_a = a->flow_type;
++ flow_type_b = b->flow_type;
++
++ /* No need to compare two rules with different tunnel types or
++ * with the same protocol type.
++ */
++ if (existing_conf->ttype != conf->ttype ||
++ flow_type_a == flow_type_b)
++ continue;
++
++ switch (flow_type_a) {
++ case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
++ case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
++ case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
++ if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
++ return true;
++ break;
++ case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
++ if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
++ flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
++ flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP)
++ return true;
++ break;
++ case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
++ case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
++ case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
++ if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER)
++ return true;
++ break;
++ case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
++ if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP ||
++ flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||
++ flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP)
++ return true;
++ break;
++ default:
++ break;
++ }
++ }
++
++ return false;
++}
++
+ /**
+ * ice_vc_fdir_write_flow_prof
+ * @vf: pointer to the VF structure
+@@ -677,6 +743,13 @@ ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
+ enum ice_fltr_ptype flow;
+ int ret;
+
++ ret = ice_vc_fdir_has_prof_conflict(vf, conf);
++ if (ret) {
++ dev_dbg(dev, "Found flow profile conflict for VF %d\n",
++ vf->vf_id);
++ return ret;
++ }
++
+ flow = input->flow_type;
+ ret = ice_vc_fdir_alloc_prof(vf, flow);
+ if (ret) {
+diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
+index 41d935d1aaf6f..40aeaa7bd739f 100644
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
+@@ -62,35 +62,38 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
+ MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
+ MVPP22_CLS_HEK_IP4_2T,
+ MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
+- MVPP2_PRS_RI_L4_TCP,
++ MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
+ MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
+ MVPP22_CLS_HEK_IP4_2T,
+ MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
+- MVPP2_PRS_RI_L4_TCP,
++ MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
+ MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_UNTAG,
+ MVPP22_CLS_HEK_IP4_2T,
+ MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
+- MVPP2_PRS_RI_L4_TCP,
++ MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_TCP,
+ MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
+
+ /* TCP over IPv4 flows, fragmented, with vlan tag */
+ MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
+- MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_TCP,
++ MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |
++ MVPP2_PRS_RI_L4_TCP,
+ MVPP2_PRS_IP_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
+- MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_TCP,
++ MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |
++ MVPP2_PRS_RI_L4_TCP,
+ MVPP2_PRS_IP_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_TCP4, MVPP2_FL_IP4_TCP_FRAG_TAG,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
+- MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_TCP,
++ MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |
++ MVPP2_PRS_RI_L4_TCP,
+ MVPP2_PRS_IP_MASK),
+
+ /* UDP over IPv4 flows, Not fragmented, no vlan tag */
+@@ -132,35 +135,38 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
+ MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
+ MVPP22_CLS_HEK_IP4_2T,
+ MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4 |
+- MVPP2_PRS_RI_L4_UDP,
++ MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
+ MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
+ MVPP22_CLS_HEK_IP4_2T,
+ MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OPT |
+- MVPP2_PRS_RI_L4_UDP,
++ MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
+ MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_UNTAG,
+ MVPP22_CLS_HEK_IP4_2T,
+ MVPP2_PRS_RI_VLAN_NONE | MVPP2_PRS_RI_L3_IP4_OTHER |
+- MVPP2_PRS_RI_L4_UDP,
++ MVPP2_PRS_RI_IP_FRAG_TRUE | MVPP2_PRS_RI_L4_UDP,
+ MVPP2_PRS_IP_MASK | MVPP2_PRS_RI_VLAN_MASK),
+
+ /* UDP over IPv4 flows, fragmented, with vlan tag */
+ MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
+- MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_L4_UDP,
++ MVPP2_PRS_RI_L3_IP4 | MVPP2_PRS_RI_IP_FRAG_TRUE |
++ MVPP2_PRS_RI_L4_UDP,
+ MVPP2_PRS_IP_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
+- MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_L4_UDP,
++ MVPP2_PRS_RI_L3_IP4_OPT | MVPP2_PRS_RI_IP_FRAG_TRUE |
++ MVPP2_PRS_RI_L4_UDP,
+ MVPP2_PRS_IP_MASK),
+
+ MVPP2_DEF_FLOW(MVPP22_FLOW_UDP4, MVPP2_FL_IP4_UDP_FRAG_TAG,
+ MVPP22_CLS_HEK_IP4_2T | MVPP22_CLS_HEK_TAGGED,
+- MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_L4_UDP,
++ MVPP2_PRS_RI_L3_IP4_OTHER | MVPP2_PRS_RI_IP_FRAG_TRUE |
++ MVPP2_PRS_RI_L4_UDP,
+ MVPP2_PRS_IP_MASK),
+
+ /* TCP over IPv6 flows, not fragmented, no vlan tag */
+diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
+index 75ba57bd1d46d..9af22f497a40f 100644
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
+@@ -1539,8 +1539,8 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
+ if (!priv->prs_double_vlans)
+ return -ENOMEM;
+
+- /* Double VLAN: 0x8100, 0x88A8 */
+- err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021AD,
++ /* Double VLAN: 0x88A8, 0x8100 */
++ err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021AD, ETH_P_8021Q,
+ MVPP2_PRS_PORT_MASK);
+ if (err)
+ return err;
+@@ -1607,59 +1607,45 @@ static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
+ static int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
+ {
+ struct mvpp2_prs_entry pe;
+- int tid;
+-
+- /* IPv4 over PPPoE with options */
+- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
+- MVPP2_PE_LAST_FREE_TID);
+- if (tid < 0)
+- return tid;
+-
+- memset(&pe, 0, sizeof(pe));
+- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
+- pe.index = tid;
+-
+- mvpp2_prs_match_etype(&pe, 0, PPP_IP);
+-
+- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
+- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
+- MVPP2_PRS_RI_L3_PROTO_MASK);
+- /* goto ipv4 dest-address (skip eth_type + IP-header-size - 4) */
+- mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
+- sizeof(struct iphdr) - 4,
+- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
+- /* Set L3 offset */
+- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
+- MVPP2_ETH_TYPE_LEN,
+- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+-
+- /* Update shadow table and hw entry */
+- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
+- mvpp2_prs_hw_write(priv, &pe);
++ int tid, ihl;
+
+- /* IPv4 over PPPoE without options */
+- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
+- MVPP2_PE_LAST_FREE_TID);
+- if (tid < 0)
+- return tid;
++ /* IPv4 over PPPoE with header length >= 5 */
++ for (ihl = MVPP2_PRS_IPV4_IHL_MIN; ihl <= MVPP2_PRS_IPV4_IHL_MAX; ihl++) {
++ tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
++ MVPP2_PE_LAST_FREE_TID);
++ if (tid < 0)
++ return tid;
+
+- pe.index = tid;
++ memset(&pe, 0, sizeof(pe));
++ mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
++ pe.index = tid;
+
+- mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
+- MVPP2_PRS_IPV4_HEAD |
+- MVPP2_PRS_IPV4_IHL_MIN,
+- MVPP2_PRS_IPV4_HEAD_MASK |
+- MVPP2_PRS_IPV4_IHL_MASK);
++ mvpp2_prs_match_etype(&pe, 0, PPP_IP);
++ mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
++ MVPP2_PRS_IPV4_HEAD | ihl,
++ MVPP2_PRS_IPV4_HEAD_MASK |
++ MVPP2_PRS_IPV4_IHL_MASK);
+
+- /* Clear ri before updating */
+- pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
+- pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
+- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
+- MVPP2_PRS_RI_L3_PROTO_MASK);
++ mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
++ mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
++ MVPP2_PRS_RI_L3_PROTO_MASK);
++ /* goto ipv4 dst-address (skip eth_type + IP-header-size - 4) */
++ mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
++ sizeof(struct iphdr) - 4,
++ MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
++ /* Set L3 offset */
++ mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
++ MVPP2_ETH_TYPE_LEN,
++ MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
++ /* Set L4 offset */
++ mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
++ MVPP2_ETH_TYPE_LEN + (ihl * 4),
++ MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
+
+- /* Update shadow table and hw entry */
+- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
+- mvpp2_prs_hw_write(priv, &pe);
++ /* Update shadow table and hw entry */
++ mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
++ mvpp2_prs_hw_write(priv, &pe);
++ }
+
+ /* IPv6 over PPPoE */
+ tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+index 34ea8af48c3d0..d6eed204574a9 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -438,6 +438,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
+ hwe->ib1 &= ~MTK_FOE_IB1_STATE;
+ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID);
+ dma_wmb();
++ mtk_ppe_cache_clear(ppe);
+ }
+ entry->hash = 0xffff;
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+index 28bbd1df3e305..6a72687d5b83f 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -570,6 +570,7 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
++ flow_block_cb_incref(block_cb);
+ flow_block_cb_add(block_cb, f);
+ list_add_tail(&block_cb->driver_list, &block_cb_list);
+ return 0;
+@@ -578,7 +579,7 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
+ if (!block_cb)
+ return -ENOENT;
+
+- if (flow_block_cb_decref(block_cb)) {
++ if (!flow_block_cb_decref(block_cb)) {
+ flow_block_cb_remove(block_cb, f);
+ list_del(&block_cb->driver_list);
+ }
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+index 3b5c5064cfafc..5e01de4c32037 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+@@ -4104,13 +4104,17 @@ static bool mlx5e_xsk_validate_mtu(struct net_device *netdev,
+ struct xsk_buff_pool *xsk_pool =
+ mlx5e_xsk_get_pool(&chs->params, chs->params.xsk, ix);
+ struct mlx5e_xsk_param xsk;
++ int max_xdp_mtu;
+
+ if (!xsk_pool)
+ continue;
+
+ mlx5e_build_xsk_param(xsk_pool, &xsk);
++ max_xdp_mtu = mlx5e_xdp_max_mtu(new_params, &xsk);
+
+- if (!mlx5e_validate_xsk_param(new_params, &xsk, mdev)) {
++ /* Validate XSK params and XDP MTU in advance */
++ if (!mlx5e_validate_xsk_param(new_params, &xsk, mdev) ||
++ new_params->sw_mtu > max_xdp_mtu) {
+ u32 hr = mlx5e_get_linear_rq_headroom(new_params, &xsk);
+ int max_mtu_frame, max_mtu_page, max_mtu;
+
+@@ -4120,9 +4124,9 @@ static bool mlx5e_xsk_validate_mtu(struct net_device *netdev,
+ */
+ max_mtu_frame = MLX5E_HW2SW_MTU(new_params, xsk.chunk_size - hr);
+ max_mtu_page = MLX5E_HW2SW_MTU(new_params, SKB_MAX_HEAD(0));
+- max_mtu = min(max_mtu_frame, max_mtu_page);
++ max_mtu = min3(max_mtu_frame, max_mtu_page, max_xdp_mtu);
+
+- netdev_err(netdev, "MTU %d is too big for an XSK running on channel %u. Try MTU <= %d\n",
++ netdev_err(netdev, "MTU %d is too big for an XSK running on channel %u or its redirection XDP program. Try MTU <= %d\n",
+ new_params->sw_mtu, ix, max_mtu);
+ return false;
+ }
+diff --git a/drivers/net/ethernet/mscc/ocelot_stats.c b/drivers/net/ethernet/mscc/ocelot_stats.c
+index dbd20b125ceaf..0066219bb0e89 100644
+--- a/drivers/net/ethernet/mscc/ocelot_stats.c
++++ b/drivers/net/ethernet/mscc/ocelot_stats.c
+@@ -392,7 +392,8 @@ static int ocelot_prepare_stats_regions(struct ocelot *ocelot)
+ if (!ocelot->stats_layout[i].reg)
+ continue;
+
+- if (region && ocelot->stats_layout[i].reg == last + 4) {
++ if (region && ocelot->map[SYS][ocelot->stats_layout[i].reg & REG_MASK] ==
++ ocelot->map[SYS][last & REG_MASK] + 4) {
+ region->count++;
+ } else {
+ region = devm_kzalloc(ocelot->dev, sizeof(*region),
+diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c
+index 930496cd34ed0..b50f16786c246 100644
+--- a/drivers/net/ethernet/realtek/r8169_phy_config.c
++++ b/drivers/net/ethernet/realtek/r8169_phy_config.c
+@@ -826,6 +826,9 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp,
+ /* disable phy pfm mode */
+ phy_modify_paged(phydev, 0x0a44, 0x11, BIT(7), 0);
+
++ /* disable 10m pll off */
++ phy_modify_paged(phydev, 0x0a43, 0x10, BIT(0), 0);
++
+ rtl8168g_disable_aldps(phydev);
+ rtl8168g_config_eee_phy(phydev);
+ }
+diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
+index 7022fb2005a2f..d30459dbfe8f8 100644
+--- a/drivers/net/ethernet/sfc/ef10.c
++++ b/drivers/net/ethernet/sfc/ef10.c
+@@ -1304,7 +1304,8 @@ static void efx_ef10_fini_nic(struct efx_nic *efx)
+ static int efx_ef10_init_nic(struct efx_nic *efx)
+ {
+ struct efx_ef10_nic_data *nic_data = efx->nic_data;
+- netdev_features_t hw_enc_features = 0;
++ struct net_device *net_dev = efx->net_dev;
++ netdev_features_t tun_feats, tso_feats;
+ int rc;
+
+ if (nic_data->must_check_datapath_caps) {
+@@ -1349,20 +1350,30 @@ static int efx_ef10_init_nic(struct efx_nic *efx)
+ nic_data->must_restore_piobufs = false;
+ }
+
+- /* add encapsulated checksum offload features */
++ /* encap features might change during reset if fw variant changed */
+ if (efx_has_cap(efx, VXLAN_NVGRE) && !efx_ef10_is_vf(efx))
+- hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+- /* add encapsulated TSO features */
+- if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) {
+- netdev_features_t encap_tso_features;
++ net_dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
++ else
++ net_dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+
+- encap_tso_features = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE |
+- NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM;
++ tun_feats = NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE |
++ NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM;
++ tso_feats = NETIF_F_TSO | NETIF_F_TSO6;
+
+- hw_enc_features |= encap_tso_features | NETIF_F_TSO;
+- efx->net_dev->features |= encap_tso_features;
++ if (efx_has_cap(efx, TX_TSO_V2_ENCAP)) {
++ /* If this is first nic_init, or if it is a reset and a new fw
++ * variant has added new features, enable them by default.
++ * If the features are not new, maintain their current value.
++ */
++ if (!(net_dev->hw_features & tun_feats))
++ net_dev->features |= tun_feats;
++ net_dev->hw_enc_features |= tun_feats | tso_feats;
++ net_dev->hw_features |= tun_feats;
++ } else {
++ net_dev->hw_enc_features &= ~(tun_feats | tso_feats);
++ net_dev->hw_features &= ~tun_feats;
++ net_dev->features &= ~tun_feats;
+ }
+- efx->net_dev->hw_enc_features = hw_enc_features;
+
+ /* don't fail init if RSS setup doesn't work */
+ rc = efx->type->rx_push_rss_config(efx, false,
+@@ -4021,7 +4032,10 @@ static unsigned int efx_ef10_recycle_ring_size(const struct efx_nic *efx)
+ NETIF_F_HW_VLAN_CTAG_FILTER | \
+ NETIF_F_IPV6_CSUM | \
+ NETIF_F_RXHASH | \
+- NETIF_F_NTUPLE)
++ NETIF_F_NTUPLE | \
++ NETIF_F_SG | \
++ NETIF_F_RXCSUM | \
++ NETIF_F_RXALL)
+
+ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
+ .is_vf = true,
+diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
+index 3a86f1213a051..6a1bff54bc6c3 100644
+--- a/drivers/net/ethernet/sfc/efx.c
++++ b/drivers/net/ethernet/sfc/efx.c
+@@ -1001,21 +1001,18 @@ static int efx_pci_probe_post_io(struct efx_nic *efx)
+ }
+
+ /* Determine netdevice features */
+- net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
+- NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_RXALL);
+- if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) {
+- net_dev->features |= NETIF_F_TSO6;
+- if (efx_has_cap(efx, TX_TSO_V2_ENCAP))
+- net_dev->hw_enc_features |= NETIF_F_TSO6;
+- }
+- /* Check whether device supports TSO */
+- if (!efx->type->tso_versions || !efx->type->tso_versions(efx))
+- net_dev->features &= ~NETIF_F_ALL_TSO;
++ net_dev->features |= efx->type->offload_features;
++
++ /* Add TSO features */
++ if (efx->type->tso_versions && efx->type->tso_versions(efx))
++ net_dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
++
+ /* Mask for features that also apply to VLAN devices */
+ net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
+ NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
+ NETIF_F_RXCSUM);
+
++ /* Determine user configurable features */
+ net_dev->hw_features |= net_dev->features & ~efx->fixed_features;
+
+ /* Disable receiving frames with bad FCS, by default. */
+diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
+index a2e511912e6a9..a690d139e1770 100644
+--- a/drivers/net/ethernet/smsc/smsc911x.c
++++ b/drivers/net/ethernet/smsc/smsc911x.c
+@@ -1037,8 +1037,6 @@ static int smsc911x_mii_probe(struct net_device *dev)
+ return ret;
+ }
+
+- /* Indicate that the MAC is responsible for managing PHY PM */
+- phydev->mac_managed_pm = true;
+ phy_attached_info(phydev);
+
+ phy_set_max_speed(phydev, SPEED_100);
+@@ -1066,6 +1064,7 @@ static int smsc911x_mii_init(struct platform_device *pdev,
+ struct net_device *dev)
+ {
+ struct smsc911x_data *pdata = netdev_priv(dev);
++ struct phy_device *phydev;
+ int err = -ENXIO;
+
+ pdata->mii_bus = mdiobus_alloc();
+@@ -1108,6 +1107,10 @@ static int smsc911x_mii_init(struct platform_device *pdev,
+ goto err_out_free_bus_2;
+ }
+
++ phydev = phy_find_first(pdata->mii_bus);
++ if (phydev)
++ phydev->mac_managed_pm = true;
++
+ return 0;
+
+ err_out_free_bus_2:
+diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
+index ec9c130276d89..54bb072aeb2d3 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -532,7 +532,6 @@ struct mac_device_info {
+ unsigned int xlgmac;
+ unsigned int num_vlan;
+ u32 vlan_filter[32];
+- unsigned int promisc;
+ bool vlan_fail_q_en;
+ u8 vlan_fail_q;
+ };
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+index e5cfde1cbd5ce..188a00065f66c 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+@@ -481,12 +481,6 @@ static int dwmac4_add_hw_vlan_rx_fltr(struct net_device *dev,
+ if (vid > 4095)
+ return -EINVAL;
+
+- if (hw->promisc) {
+- netdev_err(dev,
+- "Adding VLAN in promisc mode not supported\n");
+- return -EPERM;
+- }
+-
+ /* Single Rx VLAN Filter */
+ if (hw->num_vlan == 1) {
+ /* For single VLAN filter, VID 0 means VLAN promiscuous */
+@@ -536,12 +530,6 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev,
+ {
+ int i, ret = 0;
+
+- if (hw->promisc) {
+- netdev_err(dev,
+- "Deleting VLAN in promisc mode not supported\n");
+- return -EPERM;
+- }
+-
+ /* Single Rx VLAN Filter */
+ if (hw->num_vlan == 1) {
+ if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) {
+@@ -566,39 +554,6 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev,
+ return ret;
+ }
+
+-static void dwmac4_vlan_promisc_enable(struct net_device *dev,
+- struct mac_device_info *hw)
+-{
+- void __iomem *ioaddr = hw->pcsr;
+- u32 value;
+- u32 hash;
+- u32 val;
+- int i;
+-
+- /* Single Rx VLAN Filter */
+- if (hw->num_vlan == 1) {
+- dwmac4_write_single_vlan(dev, 0);
+- return;
+- }
+-
+- /* Extended Rx VLAN Filter Enable */
+- for (i = 0; i < hw->num_vlan; i++) {
+- if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) {
+- val = hw->vlan_filter[i] & ~GMAC_VLAN_TAG_DATA_VEN;
+- dwmac4_write_vlan_filter(dev, hw, i, val);
+- }
+- }
+-
+- hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE);
+- if (hash & GMAC_VLAN_VLHT) {
+- value = readl(ioaddr + GMAC_VLAN_TAG);
+- if (value & GMAC_VLAN_VTHM) {
+- value &= ~GMAC_VLAN_VTHM;
+- writel(value, ioaddr + GMAC_VLAN_TAG);
+- }
+- }
+-}
+-
+ static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev,
+ struct mac_device_info *hw)
+ {
+@@ -718,22 +673,12 @@ static void dwmac4_set_filter(struct mac_device_info *hw,
+ }
+
+ /* VLAN filtering */
+- if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
++ if (dev->flags & IFF_PROMISC && !hw->vlan_fail_q_en)
++ value &= ~GMAC_PACKET_FILTER_VTFE;
++ else if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
+ value |= GMAC_PACKET_FILTER_VTFE;
+
+ writel(value, ioaddr + GMAC_PACKET_FILTER);
+-
+- if (dev->flags & IFF_PROMISC && !hw->vlan_fail_q_en) {
+- if (!hw->promisc) {
+- hw->promisc = 1;
+- dwmac4_vlan_promisc_enable(dev, hw);
+- }
+- } else {
+- if (hw->promisc) {
+- hw->promisc = 0;
+- dwmac4_restore_hw_vlan_rx_fltr(dev, hw);
+- }
+- }
+ }
+
+ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
+diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+index 00911e9360525..8ff1c84a23ce7 100644
+--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
++++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+@@ -2817,6 +2817,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
+
+ err_free_phylink:
+ am65_cpsw_nuss_phylink_cleanup(common);
++ am65_cpts_release(common->cpts);
+ err_of_clear:
+ of_platform_device_destroy(common->mdio_dev, NULL);
+ err_pm_clear:
+@@ -2845,6 +2846,7 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
+ */
+ am65_cpsw_nuss_cleanup_ndev(common);
+ am65_cpsw_nuss_phylink_cleanup(common);
++ am65_cpts_release(common->cpts);
+
+ of_platform_device_destroy(common->mdio_dev, NULL);
+
+diff --git a/drivers/net/ethernet/ti/am65-cpts.c b/drivers/net/ethernet/ti/am65-cpts.c
+index e2f0fb286143b..9948ac14e68db 100644
+--- a/drivers/net/ethernet/ti/am65-cpts.c
++++ b/drivers/net/ethernet/ti/am65-cpts.c
+@@ -918,14 +918,13 @@ static int am65_cpts_of_parse(struct am65_cpts *cpts, struct device_node *node)
+ return cpts_of_mux_clk_setup(cpts, node);
+ }
+
+-static void am65_cpts_release(void *data)
++void am65_cpts_release(struct am65_cpts *cpts)
+ {
+- struct am65_cpts *cpts = data;
+-
+ ptp_clock_unregister(cpts->ptp_clock);
+ am65_cpts_disable(cpts);
+ clk_disable_unprepare(cpts->refclk);
+ }
++EXPORT_SYMBOL_GPL(am65_cpts_release);
+
+ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs,
+ struct device_node *node)
+@@ -1003,18 +1002,12 @@ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs,
+ }
+ cpts->phc_index = ptp_clock_index(cpts->ptp_clock);
+
+- ret = devm_add_action_or_reset(dev, am65_cpts_release, cpts);
+- if (ret) {
+- dev_err(dev, "failed to add ptpclk reset action %d", ret);
+- return ERR_PTR(ret);
+- }
+-
+ ret = devm_request_threaded_irq(dev, cpts->irq, NULL,
+ am65_cpts_interrupt,
+ IRQF_ONESHOT, dev_name(dev), cpts);
+ if (ret < 0) {
+ dev_err(cpts->dev, "error attaching irq %d\n", ret);
+- return ERR_PTR(ret);
++ goto reset_ptpclk;
+ }
+
+ dev_info(dev, "CPTS ver 0x%08x, freq:%u, add_val:%u\n",
+@@ -1023,6 +1016,8 @@ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs,
+
+ return cpts;
+
++reset_ptpclk:
++ am65_cpts_release(cpts);
+ refclk_disable:
+ clk_disable_unprepare(cpts->refclk);
+ return ERR_PTR(ret);
+diff --git a/drivers/net/ethernet/ti/am65-cpts.h b/drivers/net/ethernet/ti/am65-cpts.h
+index cf9fbc28fd032..c0ae0117e5737 100644
+--- a/drivers/net/ethernet/ti/am65-cpts.h
++++ b/drivers/net/ethernet/ti/am65-cpts.h
+@@ -18,6 +18,7 @@ struct am65_cpts_estf_cfg {
+ };
+
+ #if IS_ENABLED(CONFIG_TI_K3_AM65_CPTS)
++void am65_cpts_release(struct am65_cpts *cpts);
+ struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs,
+ struct device_node *node);
+ int am65_cpts_phc_index(struct am65_cpts *cpts);
+@@ -29,6 +30,10 @@ int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx,
+ struct am65_cpts_estf_cfg *cfg);
+ void am65_cpts_estf_disable(struct am65_cpts *cpts, int idx);
+ #else
++static inline void am65_cpts_release(struct am65_cpts *cpts)
++{
++}
++
+ static inline struct am65_cpts *am65_cpts_create(struct device *dev,
+ void __iomem *regs,
+ struct device_node *node)
+diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
+index 0b0c6c0764fe9..d0b5129439ed6 100644
+--- a/drivers/net/ieee802154/ca8210.c
++++ b/drivers/net/ieee802154/ca8210.c
+@@ -1902,10 +1902,9 @@ static int ca8210_skb_tx(
+ struct ca8210_priv *priv
+ )
+ {
+- int status;
+ struct ieee802154_hdr header = { };
+ struct secspec secspec;
+- unsigned int mac_len;
++ int mac_len, status;
+
+ dev_dbg(&priv->spi->dev, "%s called\n", __func__);
+
+diff --git a/drivers/net/ipa/gsi_trans.c b/drivers/net/ipa/gsi_trans.c
+index 26b7f683a3e17..fa6863c265eb9 100644
+--- a/drivers/net/ipa/gsi_trans.c
++++ b/drivers/net/ipa/gsi_trans.c
+@@ -153,7 +153,7 @@ int gsi_trans_pool_init_dma(struct device *dev, struct gsi_trans_pool *pool,
+ * gsi_trans_pool_exit_dma() can assume the total allocated
+ * size is exactly (count * size).
+ */
+- total_size = get_order(total_size) << PAGE_SHIFT;
++ total_size = PAGE_SIZE << get_order(total_size);
+
+ virt = dma_alloc_coherent(dev, total_size, &addr, GFP_KERNEL);
+ if (!virt)
+diff --git a/drivers/net/net_failover.c b/drivers/net/net_failover.c
+index 7a28e082436e4..d0c916a53d7ce 100644
+--- a/drivers/net/net_failover.c
++++ b/drivers/net/net_failover.c
+@@ -130,14 +130,10 @@ static u16 net_failover_select_queue(struct net_device *dev,
+ txq = ops->ndo_select_queue(primary_dev, skb, sb_dev);
+ else
+ txq = netdev_pick_tx(primary_dev, skb, NULL);
+-
+- qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
+-
+- return txq;
++ } else {
++ txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
+ }
+
+- txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
+-
+ /* Save the original txq to restore before passing to the driver */
+ qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
+
+diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c
+index b4ff9c5073a3c..9ab5eff502b71 100644
+--- a/drivers/net/phy/dp83869.c
++++ b/drivers/net/phy/dp83869.c
+@@ -588,15 +588,13 @@ static int dp83869_of_init(struct phy_device *phydev)
+ &dp83869_internal_delay[0],
+ delay_size, true);
+ if (dp83869->rx_int_delay < 0)
+- dp83869->rx_int_delay =
+- dp83869_internal_delay[DP83869_CLK_DELAY_DEF];
++ dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF;
+
+ dp83869->tx_int_delay = phy_get_internal_delay(phydev, dev,
+ &dp83869_internal_delay[0],
+ delay_size, false);
+ if (dp83869->tx_int_delay < 0)
+- dp83869->tx_int_delay =
+- dp83869_internal_delay[DP83869_CLK_DELAY_DEF];
++ dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF;
+
+ return ret;
+ }
+diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
+index 682987040ea82..da488cbb05428 100644
+--- a/drivers/net/vmxnet3/vmxnet3_drv.c
++++ b/drivers/net/vmxnet3/vmxnet3_drv.c
+@@ -1688,7 +1688,9 @@ not_lro:
+ if (unlikely(rcd->ts))
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
+
+- if (adapter->netdev->features & NETIF_F_LRO)
++ /* Use GRO callback if UPT is enabled */
++ if ((adapter->netdev->features & NETIF_F_LRO) &&
++ !rq->shared->updateRxProd)
+ netif_receive_skb(skb);
+ else
+ napi_gro_receive(&rq->napi, skb);
+diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
+index 3dbfc8a6924ed..1fcbd83f7ff2e 100644
+--- a/drivers/net/xen-netback/common.h
++++ b/drivers/net/xen-netback/common.h
+@@ -166,7 +166,7 @@ struct xenvif_queue { /* Per-queue data for xenvif */
+ struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
+ grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
+
+- struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
++ struct gnttab_copy tx_copy_ops[2 * MAX_PENDING_REQS];
+ struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+ struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
+ /* passed to gnttab_[un]map_refs with pages under (un)mapping */
+diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
+index bf627af723bf9..5c266062c08f0 100644
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -334,6 +334,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
+ struct xenvif_tx_cb {
+ u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1];
+ u8 copy_count;
++ u32 split_mask;
+ };
+
+ #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
+@@ -361,6 +362,8 @@ static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
+ struct sk_buff *skb =
+ alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN,
+ GFP_ATOMIC | __GFP_NOWARN);
++
++ BUILD_BUG_ON(sizeof(*XENVIF_TX_CB(skb)) > sizeof(skb->cb));
+ if (unlikely(skb == NULL))
+ return NULL;
+
+@@ -396,11 +399,13 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
+ nr_slots = shinfo->nr_frags + 1;
+
+ copy_count(skb) = 0;
++ XENVIF_TX_CB(skb)->split_mask = 0;
+
+ /* Create copy ops for exactly data_len bytes into the skb head. */
+ __skb_put(skb, data_len);
+ while (data_len > 0) {
+ int amount = data_len > txp->size ? txp->size : data_len;
++ bool split = false;
+
+ cop->source.u.ref = txp->gref;
+ cop->source.domid = queue->vif->domid;
+@@ -413,6 +418,13 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
+ cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb)
+ - data_len);
+
++ /* Don't cross local page boundary! */
++ if (cop->dest.offset + amount > XEN_PAGE_SIZE) {
++ amount = XEN_PAGE_SIZE - cop->dest.offset;
++ XENVIF_TX_CB(skb)->split_mask |= 1U << copy_count(skb);
++ split = true;
++ }
++
+ cop->len = amount;
+ cop->flags = GNTCOPY_source_gref;
+
+@@ -420,7 +432,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
+ pending_idx = queue->pending_ring[index];
+ callback_param(queue, pending_idx).ctx = NULL;
+ copy_pending_idx(skb, copy_count(skb)) = pending_idx;
+- copy_count(skb)++;
++ if (!split)
++ copy_count(skb)++;
+
+ cop++;
+ data_len -= amount;
+@@ -441,7 +454,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
+ nr_slots--;
+ } else {
+ /* The copy op partially covered the tx_request.
+- * The remainder will be mapped.
++ * The remainder will be mapped or copied in the next
++ * iteration.
+ */
+ txp->offset += amount;
+ txp->size -= amount;
+@@ -539,6 +553,13 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
+ pending_idx = copy_pending_idx(skb, i);
+
+ newerr = (*gopp_copy)->status;
++
++ /* Split copies need to be handled together. */
++ if (XENVIF_TX_CB(skb)->split_mask & (1U << i)) {
++ (*gopp_copy)++;
++ if (!newerr)
++ newerr = (*gopp_copy)->status;
++ }
+ if (likely(!newerr)) {
+ /* The first frag might still have this slot mapped */
+ if (i < copy_count(skb) - 1 || !sharedslot)
+diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
+index 81f5550b670da..8224675f8de25 100644
+--- a/drivers/nvme/host/ioctl.c
++++ b/drivers/nvme/host/ioctl.c
+@@ -387,7 +387,8 @@ static inline struct nvme_uring_cmd_pdu *nvme_uring_cmd_pdu(
+ return (struct nvme_uring_cmd_pdu *)&ioucmd->pdu;
+ }
+
+-static void nvme_uring_task_meta_cb(struct io_uring_cmd *ioucmd)
++static void nvme_uring_task_meta_cb(struct io_uring_cmd *ioucmd,
++ unsigned issue_flags)
+ {
+ struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd);
+ struct request *req = pdu->req;
+@@ -408,17 +409,18 @@ static void nvme_uring_task_meta_cb(struct io_uring_cmd *ioucmd)
+ blk_rq_unmap_user(req->bio);
+ blk_mq_free_request(req);
+
+- io_uring_cmd_done(ioucmd, status, result);
++ io_uring_cmd_done(ioucmd, status, result, issue_flags);
+ }
+
+-static void nvme_uring_task_cb(struct io_uring_cmd *ioucmd)
++static void nvme_uring_task_cb(struct io_uring_cmd *ioucmd,
++ unsigned issue_flags)
+ {
+ struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd);
+
+ if (pdu->bio)
+ blk_rq_unmap_user(pdu->bio);
+
+- io_uring_cmd_done(ioucmd, pdu->nvme_status, pdu->u.result);
++ io_uring_cmd_done(ioucmd, pdu->nvme_status, pdu->u.result, issue_flags);
+ }
+
+ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
+@@ -440,7 +442,7 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
+ * Otherwise, move the completion to task work.
+ */
+ if (cookie != NULL && blk_rq_is_poll(req))
+- nvme_uring_task_cb(ioucmd);
++ nvme_uring_task_cb(ioucmd, IO_URING_F_UNLOCKED);
+ else
+ io_uring_cmd_complete_in_task(ioucmd, nvme_uring_task_cb);
+
+@@ -462,7 +464,7 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io_meta(struct request *req,
+ * Otherwise, move the completion to task work.
+ */
+ if (cookie != NULL && blk_rq_is_poll(req))
+- nvme_uring_task_meta_cb(ioucmd);
++ nvme_uring_task_meta_cb(ioucmd, IO_URING_F_UNLOCKED);
+ else
+ io_uring_cmd_complete_in_task(ioucmd, nvme_uring_task_meta_cb);
+
+diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
+index 100f774bc97fa..60452f6a9f711 100644
+--- a/drivers/nvme/host/pci.c
++++ b/drivers/nvme/host/pci.c
+@@ -3547,6 +3547,8 @@ static const struct pci_device_id nvme_id_table[] = {
+ .driver_data = NVME_QUIRK_BOGUS_NID, },
+ { PCI_DEVICE(0x1d97, 0x2263), /* Lexar NM610 */
+ .driver_data = NVME_QUIRK_BOGUS_NID, },
++ { PCI_DEVICE(0x1d97, 0x1d97), /* Lexar NM620 */
++ .driver_data = NVME_QUIRK_BOGUS_NID, },
+ { PCI_DEVICE(0x1d97, 0x2269), /* Lexar NM760 */
+ .driver_data = NVME_QUIRK_BOGUS_NID, },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMAZON, 0x0061),
+diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
+index 9e4d96e5a3f5a..575834cae3b9e 100644
+--- a/drivers/pci/controller/dwc/pcie-designware.c
++++ b/drivers/pci/controller/dwc/pcie-designware.c
+@@ -645,11 +645,6 @@ void dw_pcie_setup(struct dw_pcie *pci)
+ dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+ }
+
+- val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
+- val &= ~PORT_LINK_FAST_LINK_MODE;
+- val |= PORT_LINK_DLL_LINK_EN;
+- dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
+-
+ if (of_property_read_bool(np, "snps,enable-cdm-check")) {
+ val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
+ val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
+@@ -657,6 +652,11 @@ void dw_pcie_setup(struct dw_pcie *pci)
+ dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
+ }
+
++ val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
++ val &= ~PORT_LINK_FAST_LINK_MODE;
++ val |= PORT_LINK_DLL_LINK_EN;
++ dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
++
+ of_property_read_u32(np, "num-lanes", &pci->num_lanes);
+ if (!pci->num_lanes) {
+ dev_dbg(pci->dev, "Using h/w default number of lanes\n");
+diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
+index 32c3edaf90385..5e7b82a2b13d0 100644
+--- a/drivers/pinctrl/pinctrl-amd.c
++++ b/drivers/pinctrl/pinctrl-amd.c
+@@ -865,32 +865,34 @@ static const struct pinconf_ops amd_pinconf_ops = {
+ .pin_config_group_set = amd_pinconf_group_set,
+ };
+
+-static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
++static void amd_gpio_irq_init_pin(struct amd_gpio *gpio_dev, int pin)
+ {
+- struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
++ const struct pin_desc *pd;
+ unsigned long flags;
+ u32 pin_reg, mask;
+- int i;
+
+ mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3) |
+ BIT(INTERRUPT_MASK_OFF) | BIT(INTERRUPT_ENABLE_OFF) |
+ BIT(WAKE_CNTRL_OFF_S4);
+
+- for (i = 0; i < desc->npins; i++) {
+- int pin = desc->pins[i].number;
+- const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin);
+-
+- if (!pd)
+- continue;
++ pd = pin_desc_get(gpio_dev->pctrl, pin);
++ if (!pd)
++ return;
+
+- raw_spin_lock_irqsave(&gpio_dev->lock, flags);
++ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
++ pin_reg = readl(gpio_dev->base + pin * 4);
++ pin_reg &= ~mask;
++ writel(pin_reg, gpio_dev->base + pin * 4);
++ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
++}
+
+- pin_reg = readl(gpio_dev->base + i * 4);
+- pin_reg &= ~mask;
+- writel(pin_reg, gpio_dev->base + i * 4);
++static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
++{
++ struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
++ int i;
+
+- raw_spin_unlock_irqrestore(&gpio_dev->lock, flags);
+- }
++ for (i = 0; i < desc->npins; i++)
++ amd_gpio_irq_init_pin(gpio_dev, i);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
+@@ -943,8 +945,10 @@ static int amd_gpio_resume(struct device *dev)
+ for (i = 0; i < desc->npins; i++) {
+ int pin = desc->pins[i].number;
+
+- if (!amd_gpio_should_save(gpio_dev, pin))
++ if (!amd_gpio_should_save(gpio_dev, pin)) {
++ amd_gpio_irq_init_pin(gpio_dev, pin);
+ continue;
++ }
+
+ raw_spin_lock_irqsave(&gpio_dev->lock, flags);
+ gpio_dev->saved_regs[i] |= readl(gpio_dev->base + pin * 4) & PIN_IRQ_PENDING;
+diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
+index 7f193f2b1566a..0b7cc6f063e00 100644
+--- a/drivers/pinctrl/pinctrl-at91-pio4.c
++++ b/drivers/pinctrl/pinctrl-at91-pio4.c
+@@ -1176,7 +1176,6 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
+ dev_err(dev, "can't add the irq domain\n");
+ return -ENODEV;
+ }
+- atmel_pioctrl->irq_domain->name = "atmel gpio";
+
+ for (i = 0; i < atmel_pioctrl->npins; i++) {
+ int irq = irq_create_mapping(atmel_pioctrl->irq_domain, i);
+diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
+index 3d5995cbcb782..c1d58939dd89a 100644
+--- a/drivers/pinctrl/pinctrl-ocelot.c
++++ b/drivers/pinctrl/pinctrl-ocelot.c
+@@ -1202,7 +1202,7 @@ static int ocelot_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ regmap_update_bits(info->map, REG_ALT(0, info, pin->pin),
+ BIT(p), f << p);
+ regmap_update_bits(info->map, REG_ALT(1, info, pin->pin),
+- BIT(p), f << (p - 1));
++ BIT(p), (f >> 1) << p);
+
+ return 0;
+ }
+diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
+index de539938896e2..b501a79f2a08a 100644
+--- a/drivers/platform/surface/aggregator/bus.c
++++ b/drivers/platform/surface/aggregator/bus.c
+@@ -485,8 +485,10 @@ int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl,
+ * device, so ignore it and continue with the next one.
+ */
+ status = ssam_add_client_device(parent, ctrl, child);
+- if (status && status != -ENODEV)
++ if (status && status != -ENODEV) {
++ fwnode_handle_put(child);
+ goto err;
++ }
+ }
+
+ return 0;
+diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
+index 4e28c55f0ea52..bd38c7dcae347 100644
+--- a/drivers/platform/x86/ideapad-laptop.c
++++ b/drivers/platform/x86/ideapad-laptop.c
+@@ -1164,7 +1164,6 @@ static const struct key_entry ideapad_keymap[] = {
+ { KE_KEY, 65, { KEY_PROG4 } },
+ { KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
+ { KE_KEY, 67, { KEY_TOUCHPAD_ON } },
+- { KE_KEY, 68, { KEY_TOUCHPAD_TOGGLE } },
+ { KE_KEY, 128, { KEY_ESC } },
+
+ /*
+@@ -1520,18 +1519,16 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_
+ if (priv->features.ctrl_ps2_aux_port)
+ i8042_command(&param, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE);
+
+- if (send_events) {
+- /*
+- * On older models the EC controls the touchpad and toggles it
+- * on/off itself, in this case we report KEY_TOUCHPAD_ON/_OFF.
+- * If the EC did not toggle, report KEY_TOUCHPAD_TOGGLE.
+- */
+- if (value != priv->r_touchpad_val) {
+- ideapad_input_report(priv, value ? 67 : 66);
+- sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
+- } else {
+- ideapad_input_report(priv, 68);
+- }
++ /*
++ * On older models the EC controls the touchpad and toggles it on/off
++ * itself, in this case we report KEY_TOUCHPAD_ON/_OFF. Some models do
++ * an acpi-notify with VPC bit 5 set on resume, so this function get
++ * called with send_events=true on every resume. Therefor if the EC did
++ * not toggle, do nothing to avoid sending spurious KEY_TOUCHPAD_TOGGLE.
++ */
++ if (send_events && value != priv->r_touchpad_val) {
++ ideapad_input_report(priv, value ? 67 : 66);
++ sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
+ }
+
+ priv->r_touchpad_val = value;
+diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
+index 17ec5825d13d7..be0fb9401202a 100644
+--- a/drivers/platform/x86/intel/pmc/core.c
++++ b/drivers/platform/x86/intel/pmc/core.c
+@@ -958,7 +958,18 @@ static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int reg_offset,
+
+ static inline u64 pmc_core_adjust_slp_s0_step(struct pmc_dev *pmcdev, u32 value)
+ {
+- return (u64)value * pmcdev->map->slp_s0_res_counter_step;
++ /*
++ * ADL PCH does not have the SLP_S0 counter and LPM Residency counters are
++ * used as a workaround which uses 30.5 usec tick. All other client
++ * programs have the legacy SLP_S0 residency counter that is using the 122
++ * usec tick.
++ */
++ const int lpm_adj_x2 = pmcdev->map->lpm_res_counter_step_x2;
++
++ if (pmcdev->map == &adl_reg_map)
++ return (u64)value * GET_X2_COUNTER((u64)lpm_adj_x2);
++ else
++ return (u64)value * pmcdev->map->slp_s0_res_counter_step;
+ }
+
+ static int set_etr3(struct pmc_dev *pmcdev)
+diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
+index a01a92769c1a3..74af3e593b2ca 100644
+--- a/drivers/platform/x86/think-lmi.c
++++ b/drivers/platform/x86/think-lmi.c
+@@ -941,12 +941,23 @@ static ssize_t possible_values_show(struct kobject *kobj, struct kobj_attribute
+ {
+ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
+
+- if (!tlmi_priv.can_get_bios_selections)
+- return -EOPNOTSUPP;
+-
+ return sysfs_emit(buf, "%s\n", setting->possible_values);
+ }
+
++static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
++
++ if (setting->possible_values) {
++ /* Figure out what setting type is as BIOS does not return this */
++ if (strchr(setting->possible_values, ';'))
++ return sysfs_emit(buf, "enumeration\n");
++ }
++ /* Anything else is going to be a string */
++ return sysfs_emit(buf, "string\n");
++}
++
+ static ssize_t current_value_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+@@ -1036,14 +1047,30 @@ static struct kobj_attribute attr_possible_values = __ATTR_RO(possible_values);
+
+ static struct kobj_attribute attr_current_val = __ATTR_RW_MODE(current_value, 0600);
+
++static struct kobj_attribute attr_type = __ATTR_RO(type);
++
++static umode_t attr_is_visible(struct kobject *kobj,
++ struct attribute *attr, int n)
++{
++ struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj);
++
++ /* We don't want to display possible_values attributes if not available */
++ if ((attr == &attr_possible_values.attr) && (!setting->possible_values))
++ return 0;
++
++ return attr->mode;
++}
++
+ static struct attribute *tlmi_attrs[] = {
+ &attr_displ_name.attr,
+ &attr_current_val.attr,
+ &attr_possible_values.attr,
++ &attr_type.attr,
+ NULL
+ };
+
+ static const struct attribute_group tlmi_attr_group = {
++ .is_visible = attr_is_visible,
+ .attrs = tlmi_attrs,
+ };
+
+@@ -1423,7 +1450,34 @@ static int tlmi_analyze(void)
+ if (ret || !setting->possible_values)
+ pr_info("Error retrieving possible values for %d : %s\n",
+ i, setting->display_name);
++ } else {
++ /*
++ * Older Thinkstations don't support the bios_selections API.
++ * Instead they store this as a [Optional:Option1,Option2] section of the
++ * name string.
++ * Try and pull that out if it's available.
++ */
++ char *item, *optstart, *optend;
++
++ if (!tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID)) {
++ optstart = strstr(item, "[Optional:");
++ if (optstart) {
++ optstart += strlen("[Optional:");
++ optend = strstr(optstart, "]");
++ if (optend)
++ setting->possible_values =
++ kstrndup(optstart, optend - optstart,
++ GFP_KERNEL);
++ }
++ }
+ }
++ /*
++ * firmware-attributes requires that possible_values are separated by ';' but
++ * Lenovo FW uses ','. Replace appropriately.
++ */
++ if (setting->possible_values)
++ strreplace(setting->possible_values, ',', ';');
++
+ kobject_init(&setting->kobj, &tlmi_attr_setting_ktype);
+ tlmi_priv.setting[i] = setting;
+ kfree(item);
+diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c
+index 08f4cf0ad9e3c..8fa9772acf79b 100644
+--- a/drivers/ptp/ptp_qoriq.c
++++ b/drivers/ptp/ptp_qoriq.c
+@@ -601,7 +601,7 @@ static int ptp_qoriq_probe(struct platform_device *dev)
+ return 0;
+
+ no_clock:
+- iounmap(ptp_qoriq->base);
++ iounmap(base);
+ no_ioremap:
+ release_resource(ptp_qoriq->rsrc);
+ no_resource:
+diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
+index 2a9867abba20c..e6724a229d237 100644
+--- a/drivers/regulator/fixed.c
++++ b/drivers/regulator/fixed.c
+@@ -215,7 +215,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
+ drvdata->enable_clock = devm_clk_get(dev, NULL);
+ if (IS_ERR(drvdata->enable_clock)) {
+ dev_err(dev, "Can't get enable-clock from devicetree\n");
+- return -ENOENT;
++ return PTR_ERR(drvdata->enable_clock);
+ }
+ } else if (drvtype && drvtype->has_performance_state) {
+ drvdata->desc.ops = &fixed_voltage_domain_ops;
+diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c
+index f43cfeabd2cc8..0afceb63ac43c 100644
+--- a/drivers/s390/crypto/vfio_ap_drv.c
++++ b/drivers/s390/crypto/vfio_ap_drv.c
+@@ -54,8 +54,9 @@ static struct ap_driver vfio_ap_drv = {
+
+ static void vfio_ap_matrix_dev_release(struct device *dev)
+ {
+- struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev);
++ struct ap_matrix_dev *matrix_dev;
+
++ matrix_dev = container_of(dev, struct ap_matrix_dev, device);
+ kfree(matrix_dev);
+ }
+
+diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+index 6650f8c8e9b04..af22ffa8f6a25 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
+@@ -4768,7 +4768,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
+ devhandle = megasas_get_tm_devhandle(scmd->device);
+
+ if (devhandle == (u16)ULONG_MAX) {
+- ret = SUCCESS;
++ ret = FAILED;
+ sdev_printk(KERN_INFO, scmd->device,
+ "task abort issued for invalid devhandle\n");
+ mutex_unlock(&instance->reset_mutex);
+@@ -4838,7 +4838,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
+ devhandle = megasas_get_tm_devhandle(scmd->device);
+
+ if (devhandle == (u16)ULONG_MAX) {
+- ret = SUCCESS;
++ ret = FAILED;
+ sdev_printk(KERN_INFO, scmd->device,
+ "target reset issued for invalid devhandle\n");
+ mutex_unlock(&instance->reset_mutex);
+diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
+index 2ee9ea57554d7..14ae0a9c5d3d8 100644
+--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
++++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
+@@ -6616,11 +6616,6 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
+ else if (rc == -EAGAIN)
+ goto try_32bit_dma;
+ total_sz += sense_sz;
+- ioc_info(ioc,
+- "sense pool(0x%p)- dma(0x%llx): depth(%d),"
+- "element_size(%d), pool_size(%d kB)\n",
+- ioc->sense, (unsigned long long)ioc->sense_dma, ioc->scsiio_depth,
+- SCSI_SENSE_BUFFERSIZE, sz / 1024);
+ /* reply pool, 4 byte align */
+ sz = ioc->reply_free_queue_depth * ioc->reply_sz;
+ rc = _base_allocate_reply_pool(ioc, sz);
+diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c
+index ae28a03fa890b..1157b8869bcca 100644
+--- a/drivers/thunderbolt/quirks.c
++++ b/drivers/thunderbolt/quirks.c
+@@ -26,6 +26,19 @@ static void quirk_clx_disable(struct tb_switch *sw)
+ tb_sw_dbg(sw, "disabling CL states\n");
+ }
+
++static void quirk_usb3_maximum_bandwidth(struct tb_switch *sw)
++{
++ struct tb_port *port;
++
++ tb_switch_for_each_port(sw, port) {
++ if (!tb_port_is_usb3_down(port))
++ continue;
++ port->max_bw = 16376;
++ tb_port_dbg(port, "USB3 maximum bandwidth limited to %u Mb/s\n",
++ port->max_bw);
++ }
++}
++
+ struct tb_quirk {
+ u16 hw_vendor_id;
+ u16 hw_device_id;
+@@ -43,6 +56,24 @@ static const struct tb_quirk tb_quirks[] = {
+ * DP buffers.
+ */
+ { 0x8087, 0x0b26, 0x0000, 0x0000, quirk_dp_credit_allocation },
++ /*
++ * Limit the maximum USB3 bandwidth for the following Intel USB4
++ * host routers due to a hardware issue.
++ */
++ { 0x8087, PCI_DEVICE_ID_INTEL_ADL_NHI0, 0x0000, 0x0000,
++ quirk_usb3_maximum_bandwidth },
++ { 0x8087, PCI_DEVICE_ID_INTEL_ADL_NHI1, 0x0000, 0x0000,
++ quirk_usb3_maximum_bandwidth },
++ { 0x8087, PCI_DEVICE_ID_INTEL_RPL_NHI0, 0x0000, 0x0000,
++ quirk_usb3_maximum_bandwidth },
++ { 0x8087, PCI_DEVICE_ID_INTEL_RPL_NHI1, 0x0000, 0x0000,
++ quirk_usb3_maximum_bandwidth },
++ { 0x8087, PCI_DEVICE_ID_INTEL_MTL_M_NHI0, 0x0000, 0x0000,
++ quirk_usb3_maximum_bandwidth },
++ { 0x8087, PCI_DEVICE_ID_INTEL_MTL_P_NHI0, 0x0000, 0x0000,
++ quirk_usb3_maximum_bandwidth },
++ { 0x8087, PCI_DEVICE_ID_INTEL_MTL_P_NHI1, 0x0000, 0x0000,
++ quirk_usb3_maximum_bandwidth },
+ /*
+ * CLx is not supported on AMD USB4 Yellow Carp and Pink Sardine platforms.
+ */
+diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
+index e11d973a8f9b6..f034723b1b40e 100644
+--- a/drivers/thunderbolt/tb.h
++++ b/drivers/thunderbolt/tb.h
+@@ -252,6 +252,8 @@ struct tb_switch {
+ * @ctl_credits: Buffers reserved for control path
+ * @dma_credits: Number of credits allocated for DMA tunneling for all
+ * DMA paths through this port.
++ * @max_bw: Maximum possible bandwidth through this adapter if set to
++ * non-zero.
+ *
+ * In USB4 terminology this structure represents an adapter (protocol or
+ * lane adapter).
+@@ -277,6 +279,7 @@ struct tb_port {
+ unsigned int total_credits;
+ unsigned int ctl_credits;
+ unsigned int dma_credits;
++ unsigned int max_bw;
+ };
+
+ /**
+diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c
+index cf8d4f769579e..3c821f5e44814 100644
+--- a/drivers/thunderbolt/usb4.c
++++ b/drivers/thunderbolt/usb4.c
+@@ -1865,6 +1865,15 @@ int usb4_port_retimer_nvm_read(struct tb_port *port, u8 index,
+ usb4_port_retimer_nvm_read_block, &info);
+ }
+
++static inline unsigned int
++usb4_usb3_port_max_bandwidth(const struct tb_port *port, unsigned int bw)
++{
++ /* Take the possible bandwidth limitation into account */
++ if (port->max_bw)
++ return min(bw, port->max_bw);
++ return bw;
++}
++
+ /**
+ * usb4_usb3_port_max_link_rate() - Maximum support USB3 link rate
+ * @port: USB3 adapter port
+@@ -1886,7 +1895,9 @@ int usb4_usb3_port_max_link_rate(struct tb_port *port)
+ return ret;
+
+ lr = (val & ADP_USB3_CS_4_MSLR_MASK) >> ADP_USB3_CS_4_MSLR_SHIFT;
+- return lr == ADP_USB3_CS_4_MSLR_20G ? 20000 : 10000;
++ ret = lr == ADP_USB3_CS_4_MSLR_20G ? 20000 : 10000;
++
++ return usb4_usb3_port_max_bandwidth(port, ret);
+ }
+
+ /**
+@@ -1913,7 +1924,9 @@ int usb4_usb3_port_actual_link_rate(struct tb_port *port)
+ return 0;
+
+ lr = val & ADP_USB3_CS_4_ALR_MASK;
+- return lr == ADP_USB3_CS_4_ALR_20G ? 20000 : 10000;
++ ret = lr == ADP_USB3_CS_4_ALR_20G ? 20000 : 10000;
++
++ return usb4_usb3_port_max_bandwidth(port, ret);
+ }
+
+ static int usb4_usb3_port_cm_request(struct tb_port *port, bool request)
+diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
+index c51883f34ac2b..cd98c04de0330 100644
+--- a/drivers/tty/serial/fsl_lpuart.c
++++ b/drivers/tty/serial/fsl_lpuart.c
+@@ -582,7 +582,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
+ sport->dma_tx_nents, DMA_TO_DEVICE);
+ sport->dma_tx_in_progress = false;
+ }
+- dmaengine_terminate_all(chan);
++ dmaengine_terminate_async(chan);
+ }
+
+ if (lpuart_is_32(sport)) {
+@@ -1333,7 +1333,8 @@ static void lpuart_dma_rx_free(struct uart_port *port)
+ struct lpuart_port, port);
+ struct dma_chan *chan = sport->dma_rx_chan;
+
+- dmaengine_terminate_all(chan);
++ dmaengine_terminate_sync(chan);
++ del_timer_sync(&sport->lpuart_timer);
+ dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+ kfree(sport->rx_ring.buf);
+ sport->rx_ring.tail = 0;
+@@ -1757,7 +1758,6 @@ static int lpuart32_startup(struct uart_port *port)
+ static void lpuart_dma_shutdown(struct lpuart_port *sport)
+ {
+ if (sport->lpuart_dma_rx_use) {
+- del_timer_sync(&sport->lpuart_timer);
+ lpuart_dma_rx_free(&sport->port);
+ sport->lpuart_dma_rx_use = false;
+ }
+@@ -1766,7 +1766,7 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport)
+ if (wait_event_interruptible_timeout(sport->dma_wait,
+ !sport->dma_tx_in_progress, msecs_to_jiffies(300)) <= 0) {
+ sport->dma_tx_in_progress = false;
+- dmaengine_terminate_all(sport->dma_tx_chan);
++ dmaengine_terminate_sync(sport->dma_tx_chan);
+ }
+ sport->lpuart_dma_tx_use = false;
+ }
+@@ -1917,10 +1917,8 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
+ * Since timer function acqures sport->port.lock, need to stop before
+ * acquring same lock because otherwise del_timer_sync() can deadlock.
+ */
+- if (old && sport->lpuart_dma_rx_use) {
+- del_timer_sync(&sport->lpuart_timer);
++ if (old && sport->lpuart_dma_rx_use)
+ lpuart_dma_rx_free(&sport->port);
+- }
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+@@ -2154,10 +2152,8 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
+ * Since timer function acqures sport->port.lock, need to stop before
+ * acquring same lock because otherwise del_timer_sync() can deadlock.
+ */
+- if (old && sport->lpuart_dma_rx_use) {
+- del_timer_sync(&sport->lpuart_timer);
++ if (old && sport->lpuart_dma_rx_use)
+ lpuart_dma_rx_free(&sport->port);
+- }
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+@@ -2850,7 +2846,6 @@ static int __maybe_unused lpuart_suspend(struct device *dev)
+ * Rx DMA path before suspend and start Rx DMA path on resume.
+ */
+ if (irq_wake) {
+- del_timer_sync(&sport->lpuart_timer);
+ lpuart_dma_rx_free(&sport->port);
+ }
+
+@@ -2867,7 +2862,7 @@ static int __maybe_unused lpuart_suspend(struct device *dev)
+
+ if (sport->lpuart_dma_tx_use) {
+ sport->dma_tx_in_progress = false;
+- dmaengine_terminate_all(sport->dma_tx_chan);
++ dmaengine_terminate_sync(sport->dma_tx_chan);
+ }
+
+ if (sport->port.suspended && !irq_wake)
+diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
+index 8cbbb002fefe0..086b509689839 100644
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -1039,9 +1039,8 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con)
+ return NULL;
+ }
+
+-static int ucsi_register_port(struct ucsi *ucsi, int index)
++static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
+ {
+- struct ucsi_connector *con = &ucsi->connector[index];
+ struct typec_capability *cap = &con->typec_cap;
+ enum typec_accessory *accessory = cap->accessory;
+ enum usb_role u_role = USB_ROLE_NONE;
+@@ -1062,7 +1061,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
+ init_completion(&con->complete);
+ mutex_init(&con->lock);
+ INIT_LIST_HEAD(&con->partner_tasks);
+- con->num = index + 1;
+ con->ucsi = ucsi;
+
+ cap->fwnode = ucsi_find_fwnode(con);
+@@ -1204,7 +1202,7 @@ out_unlock:
+ */
+ static int ucsi_init(struct ucsi *ucsi)
+ {
+- struct ucsi_connector *con;
++ struct ucsi_connector *con, *connector;
+ u64 command, ntfy;
+ int ret;
+ int i;
+@@ -1235,16 +1233,16 @@ static int ucsi_init(struct ucsi *ucsi)
+ }
+
+ /* Allocate the connectors. Released in ucsi_unregister() */
+- ucsi->connector = kcalloc(ucsi->cap.num_connectors + 1,
+- sizeof(*ucsi->connector), GFP_KERNEL);
+- if (!ucsi->connector) {
++ connector = kcalloc(ucsi->cap.num_connectors + 1, sizeof(*connector), GFP_KERNEL);
++ if (!connector) {
+ ret = -ENOMEM;
+ goto err_reset;
+ }
+
+ /* Register all connectors */
+ for (i = 0; i < ucsi->cap.num_connectors; i++) {
+- ret = ucsi_register_port(ucsi, i);
++ connector[i].num = i + 1;
++ ret = ucsi_register_port(ucsi, &connector[i]);
+ if (ret)
+ goto err_unregister;
+ }
+@@ -1256,11 +1254,12 @@ static int ucsi_init(struct ucsi *ucsi)
+ if (ret < 0)
+ goto err_unregister;
+
++ ucsi->connector = connector;
+ ucsi->ntfy = ntfy;
+ return 0;
+
+ err_unregister:
+- for (con = ucsi->connector; con->port; con++) {
++ for (con = connector; con->port; con++) {
+ ucsi_unregister_partner(con);
+ ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
+ ucsi_unregister_port_psy(con);
+@@ -1269,10 +1268,7 @@ err_unregister:
+ typec_unregister_port(con->port);
+ con->port = NULL;
+ }
+-
+- kfree(ucsi->connector);
+- ucsi->connector = NULL;
+-
++ kfree(connector);
+ err_reset:
+ memset(&ucsi->cap, 0, sizeof(ucsi->cap));
+ ucsi_reset_ppm(ucsi);
+diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c
+index 81c3154544287..b6b22fa4a8a01 100644
+--- a/drivers/video/fbdev/au1200fb.c
++++ b/drivers/video/fbdev/au1200fb.c
+@@ -1040,6 +1040,9 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
+ u32 pixclock;
+ int screen_size, plane;
+
++ if (!var->pixclock)
++ return -EINVAL;
++
+ plane = fbdev->plane;
+
+ /* Make sure that the mode respect all LCD controller and
+diff --git a/drivers/video/fbdev/geode/lxfb_core.c b/drivers/video/fbdev/geode/lxfb_core.c
+index 9d26592dbfce9..41fda498406c1 100644
+--- a/drivers/video/fbdev/geode/lxfb_core.c
++++ b/drivers/video/fbdev/geode/lxfb_core.c
+@@ -235,6 +235,9 @@ static void get_modedb(struct fb_videomode **modedb, unsigned int *size)
+
+ static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
++ if (!var->pixclock)
++ return -EINVAL;
++
+ if (var->xres > 1920 || var->yres > 1440)
+ return -EINVAL;
+
+diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c
+index d4a2891a9a7ac..a93dd531d00df 100644
+--- a/drivers/video/fbdev/intelfb/intelfbdrv.c
++++ b/drivers/video/fbdev/intelfb/intelfbdrv.c
+@@ -1219,6 +1219,9 @@ static int intelfb_check_var(struct fb_var_screeninfo *var,
+
+ dinfo = GET_DINFO(info);
+
++ if (!var->pixclock)
++ return -EINVAL;
++
+ /* update the pitch */
+ if (intelfbhw_validate_mode(dinfo, var) != 0)
+ return -EINVAL;
+diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c
+index a6c3bc2222463..1b8904824ad83 100644
+--- a/drivers/video/fbdev/nvidia/nvidia.c
++++ b/drivers/video/fbdev/nvidia/nvidia.c
+@@ -764,6 +764,8 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var,
+ int pitch, err = 0;
+
+ NVTRACE_ENTER();
++ if (!var->pixclock)
++ return -EINVAL;
+
+ var->transp.offset = 0;
+ var->transp.length = 0;
+diff --git a/drivers/video/fbdev/tgafb.c b/drivers/video/fbdev/tgafb.c
+index 251dbd282f5ed..84d5daef97666 100644
+--- a/drivers/video/fbdev/tgafb.c
++++ b/drivers/video/fbdev/tgafb.c
+@@ -173,6 +173,9 @@ tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+ struct tga_par *par = (struct tga_par *)info->par;
+
++ if (!var->pixclock)
++ return -EINVAL;
++
+ if (par->tga_type == TGA_TYPE_8PLANE) {
+ if (var->bits_per_pixel != 8)
+ return -EINVAL;
+diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
+index 4b69945755e4f..f33ddd5922b8c 100644
+--- a/fs/btrfs/block-group.c
++++ b/fs/btrfs/block-group.c
+@@ -3259,13 +3259,15 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
+ spin_unlock(&info->delalloc_root_lock);
+
+ while (total) {
+- bool reclaim;
++ struct btrfs_space_info *space_info;
++ bool reclaim = false;
+
+ cache = btrfs_lookup_block_group(info, bytenr);
+ if (!cache) {
+ ret = -ENOENT;
+ break;
+ }
++ space_info = cache->space_info;
+ factor = btrfs_bg_type_to_factor(cache->flags);
+
+ /*
+@@ -3280,7 +3282,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
+ byte_in_group = bytenr - cache->start;
+ WARN_ON(byte_in_group > cache->length);
+
+- spin_lock(&cache->space_info->lock);
++ spin_lock(&space_info->lock);
+ spin_lock(&cache->lock);
+
+ if (btrfs_test_opt(info, SPACE_CACHE) &&
+@@ -3293,23 +3295,23 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
+ old_val += num_bytes;
+ cache->used = old_val;
+ cache->reserved -= num_bytes;
+- cache->space_info->bytes_reserved -= num_bytes;
+- cache->space_info->bytes_used += num_bytes;
+- cache->space_info->disk_used += num_bytes * factor;
++ space_info->bytes_reserved -= num_bytes;
++ space_info->bytes_used += num_bytes;
++ space_info->disk_used += num_bytes * factor;
+ spin_unlock(&cache->lock);
+- spin_unlock(&cache->space_info->lock);
++ spin_unlock(&space_info->lock);
+ } else {
+ old_val -= num_bytes;
+ cache->used = old_val;
+ cache->pinned += num_bytes;
+- btrfs_space_info_update_bytes_pinned(info,
+- cache->space_info, num_bytes);
+- cache->space_info->bytes_used -= num_bytes;
+- cache->space_info->disk_used -= num_bytes * factor;
++ btrfs_space_info_update_bytes_pinned(info, space_info,
++ num_bytes);
++ space_info->bytes_used -= num_bytes;
++ space_info->disk_used -= num_bytes * factor;
+
+ reclaim = should_reclaim_block_group(cache, num_bytes);
+ spin_unlock(&cache->lock);
+- spin_unlock(&cache->space_info->lock);
++ spin_unlock(&space_info->lock);
+
+ set_extent_dirty(&trans->transaction->pinned_extents,
+ bytenr, bytenr + num_bytes - 1,
+diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
+index a3febabacec04..3bcef0c4d6fc4 100644
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -590,11 +590,8 @@ enum {
+ /* Indicate we have to finish a zone to do next allocation. */
+ BTRFS_FS_NEED_ZONE_FINISH,
+
+- /*
+- * Indicate metadata over-commit is disabled. This is set when active
+- * zone tracking is needed.
+- */
+- BTRFS_FS_NO_OVERCOMMIT,
++ /* This is set when active zone tracking is needed. */
++ BTRFS_FS_ACTIVE_ZONE_TRACKING,
+
+ #if BITS_PER_LONG == 32
+ /* Indicate if we have error/warn message printed on 32bit systems */
+diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
+index f4023651dd68b..6a8f2bd350f4b 100644
+--- a/fs/btrfs/free-space-cache.c
++++ b/fs/btrfs/free-space-cache.c
+@@ -2684,8 +2684,13 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
+ bg_reclaim_threshold = READ_ONCE(sinfo->bg_reclaim_threshold);
+
+ spin_lock(&ctl->tree_lock);
++ /* Count initial region as zone_unusable until it gets activated. */
+ if (!used)
+ to_free = size;
++ else if (initial &&
++ test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &block_group->fs_info->flags) &&
++ (block_group->flags & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM)))
++ to_free = 0;
+ else if (initial)
+ to_free = block_group->zone_capacity;
+ else if (offset >= block_group->alloc_offset)
+@@ -2713,7 +2718,8 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
+ reclaimable_unusable = block_group->zone_unusable -
+ (block_group->length - block_group->zone_capacity);
+ /* All the region is now unusable. Mark it as unused and reclaim */
+- if (block_group->zone_unusable == block_group->length) {
++ if (block_group->zone_unusable == block_group->length &&
++ block_group->alloc_offset) {
+ btrfs_mark_bg_unused(block_group);
+ } else if (bg_reclaim_threshold &&
+ reclaimable_unusable >=
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index c05f16a35bcaf..fe2fb81da46ba 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -4621,7 +4621,9 @@ static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
+ }
+
+ /* update qgroup status and info */
++ mutex_lock(&fs_info->qgroup_ioctl_lock);
+ err = btrfs_run_qgroups(trans);
++ mutex_unlock(&fs_info->qgroup_ioctl_lock);
+ if (err < 0)
+ btrfs_handle_fs_error(fs_info, err,
+ "failed to update qgroup status and info");
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index 5ac65384c9471..f8b0548988858 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -2812,13 +2812,22 @@ cleanup:
+ }
+
+ /*
+- * called from commit_transaction. Writes all changed qgroups to disk.
++ * Writes all changed qgroups to disk.
++ * Called by the transaction commit path and the qgroup assign ioctl.
+ */
+ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
+ {
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ int ret = 0;
+
++ /*
++ * In case we are called from the qgroup assign ioctl, assert that we
++ * are holding the qgroup_ioctl_lock, otherwise we can race with a quota
++ * disable operation (ioctl) and access a freed quota root.
++ */
++ if (trans->transaction->state != TRANS_STATE_COMMIT_DOING)
++ lockdep_assert_held(&fs_info->qgroup_ioctl_lock);
++
+ if (!fs_info->quota_root)
+ return ret;
+
+diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c
+index 65c010159fb5f..c7642c00a65d0 100644
+--- a/fs/btrfs/space-info.c
++++ b/fs/btrfs/space-info.c
+@@ -404,7 +404,7 @@ int btrfs_can_overcommit(struct btrfs_fs_info *fs_info,
+ return 0;
+
+ used = btrfs_space_info_used(space_info, true);
+- if (test_bit(BTRFS_FS_NO_OVERCOMMIT, &fs_info->flags) &&
++ if (test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &fs_info->flags) &&
+ (space_info->flags & BTRFS_BLOCK_GROUP_METADATA))
+ avail = 0;
+ else
+diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
+index d1f1da6820fb0..682b463a7633a 100644
+--- a/fs/btrfs/transaction.c
++++ b/fs/btrfs/transaction.c
+@@ -2009,7 +2009,20 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, int err)
+
+ if (current->journal_info == trans)
+ current->journal_info = NULL;
+- btrfs_scrub_cancel(fs_info);
++
++ /*
++ * If relocation is running, we can't cancel scrub because that will
++ * result in a deadlock. Before relocating a block group, relocation
++ * pauses scrub, then starts and commits a transaction before unpausing
++ * scrub. If the transaction commit is being done by the relocation
++ * task or triggered by another task and the relocation task is waiting
++ * for the commit, and we end up here due to an error in the commit
++ * path, then calling btrfs_scrub_cancel() will deadlock, as we are
++ * asking for scrub to stop while having it asked to be paused higher
++ * above in relocation code.
++ */
++ if (!test_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags))
++ btrfs_scrub_cancel(fs_info);
+
+ kmem_cache_free(btrfs_trans_handle_cachep, trans);
+ }
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index f02b8cbd6ec41..67b2aa552d228 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -1379,8 +1379,17 @@ struct btrfs_device *btrfs_scan_one_device(const char *path, fmode_t flags,
+ * So, we need to add a special mount option to scan for
+ * later supers, using BTRFS_SUPER_MIRROR_MAX instead
+ */
+- flags |= FMODE_EXCL;
+
++ /*
++ * Avoid using flag |= FMODE_EXCL here, as the systemd-udev may
++ * initiate the device scan which may race with the user's mount
++ * or mkfs command, resulting in failure.
++ * Since the device scan is solely for reading purposes, there is
++ * no need for FMODE_EXCL. Additionally, the devices are read again
++ * during the mount process. It is ok to get some inconsistent
++ * values temporarily, as the device paths of the fsid are the only
++ * required information for assembling the volume.
++ */
+ bdev = blkdev_get_by_path(path, flags, holder);
+ if (IS_ERR(bdev))
+ return ERR_CAST(bdev);
+@@ -3286,8 +3295,15 @@ int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset)
+ btrfs_scrub_pause(fs_info);
+ ret = btrfs_relocate_block_group(fs_info, chunk_offset);
+ btrfs_scrub_continue(fs_info);
+- if (ret)
++ if (ret) {
++ /*
++ * If we had a transaction abort, stop all running scrubs.
++ * See transaction.c:cleanup_transaction() why we do it here.
++ */
++ if (BTRFS_FS_ERROR(fs_info))
++ btrfs_scrub_cancel(fs_info);
+ return ret;
++ }
+
+ block_group = btrfs_lookup_block_group(fs_info, chunk_offset);
+ if (!block_group)
+diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
+index 1b72004136ef8..e97c5a1ac95d6 100644
+--- a/fs/btrfs/zoned.c
++++ b/fs/btrfs/zoned.c
+@@ -538,8 +538,7 @@ int btrfs_get_dev_zone_info(struct btrfs_device *device, bool populate_cache)
+ }
+ atomic_set(&zone_info->active_zones_left,
+ max_active_zones - nactive);
+- /* Overcommit does not work well with active zone tacking. */
+- set_bit(BTRFS_FS_NO_OVERCOMMIT, &fs_info->flags);
++ set_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &fs_info->flags);
+ }
+
+ /* Validate superblock log */
+@@ -1576,9 +1575,19 @@ void btrfs_calc_zone_unusable(struct btrfs_block_group *cache)
+ return;
+
+ WARN_ON(cache->bytes_super != 0);
+- unusable = (cache->alloc_offset - cache->used) +
+- (cache->length - cache->zone_capacity);
+- free = cache->zone_capacity - cache->alloc_offset;
++
++ /* Check for block groups never get activated */
++ if (test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &cache->fs_info->flags) &&
++ cache->flags & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM) &&
++ !test_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &cache->runtime_flags) &&
++ cache->alloc_offset == 0) {
++ unusable = cache->length;
++ free = 0;
++ } else {
++ unusable = (cache->alloc_offset - cache->used) +
++ (cache->length - cache->zone_capacity);
++ free = cache->zone_capacity - cache->alloc_offset;
++ }
+
+ /* We only need ->free_space in ALLOC_SEQ block groups */
+ cache->cached = BTRFS_CACHE_FINISHED;
+@@ -1915,7 +1924,11 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group)
+
+ /* Successfully activated all the zones */
+ set_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &block_group->runtime_flags);
+- space_info->active_total_bytes += block_group->length;
++ WARN_ON(block_group->alloc_offset != 0);
++ if (block_group->zone_unusable == block_group->length) {
++ block_group->zone_unusable = block_group->length - block_group->zone_capacity;
++ space_info->bytes_zone_unusable -= block_group->zone_capacity;
++ }
+ spin_unlock(&block_group->lock);
+ btrfs_try_granting_tickets(fs_info, space_info);
+ spin_unlock(&space_info->lock);
+@@ -2278,7 +2291,7 @@ int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
+ u64 avail;
+
+ spin_lock(&block_group->lock);
+- if (block_group->reserved ||
++ if (block_group->reserved || block_group->alloc_offset == 0 ||
+ (block_group->flags & BTRFS_BLOCK_GROUP_SYSTEM)) {
+ spin_unlock(&block_group->lock);
+ continue;
+diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
+index 388b745a978e2..b6c38896fb2db 100644
+--- a/fs/cifs/cifsfs.h
++++ b/fs/cifs/cifsfs.h
+@@ -118,7 +118,10 @@ extern const struct dentry_operations cifs_ci_dentry_ops;
+ #ifdef CONFIG_CIFS_DFS_UPCALL
+ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
+ #else
+-#define cifs_dfs_d_automount NULL
++static inline struct vfsmount *cifs_dfs_d_automount(struct path *path)
++{
++ return ERR_PTR(-EREMOTE);
++}
+ #endif
+
+ /* Functions related to symlinks */
+diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
+index bc4475f6c0827..98513f5af3f96 100644
+--- a/fs/cifs/cifsproto.h
++++ b/fs/cifs/cifsproto.h
+@@ -691,5 +691,6 @@ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
+
+ struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
+ void cifs_put_tcon_super(struct super_block *sb);
++int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry);
+
+ #endif /* _CIFSPROTO_H */
+diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
+index 6c6a7fc47f3e3..c90d4ec9292ca 100644
+--- a/fs/cifs/cifssmb.c
++++ b/fs/cifs/cifssmb.c
+@@ -70,7 +70,6 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
+ struct cifs_ses *ses;
+ struct TCP_Server_Info *server;
+ struct nls_table *nls_codepage;
+- int retries;
+
+ /*
+ * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
+@@ -98,45 +97,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
+ }
+ spin_unlock(&tcon->tc_lock);
+
+- retries = server->nr_targets;
+-
+- /*
+- * Give demultiplex thread up to 10 seconds to each target available for
+- * reconnect -- should be greater than cifs socket timeout which is 7
+- * seconds.
+- */
+- while (server->tcpStatus == CifsNeedReconnect) {
+- rc = wait_event_interruptible_timeout(server->response_q,
+- (server->tcpStatus != CifsNeedReconnect),
+- 10 * HZ);
+- if (rc < 0) {
+- cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
+- __func__);
+- return -ERESTARTSYS;
+- }
+-
+- /* are we still trying to reconnect? */
+- spin_lock(&server->srv_lock);
+- if (server->tcpStatus != CifsNeedReconnect) {
+- spin_unlock(&server->srv_lock);
+- break;
+- }
+- spin_unlock(&server->srv_lock);
+-
+- if (retries && --retries)
+- continue;
+-
+- /*
+- * on "soft" mounts we wait once. Hard mounts keep
+- * retrying until process is killed or server comes
+- * back on-line
+- */
+- if (!tcon->retry) {
+- cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
+- return -EHOSTDOWN;
+- }
+- retries = server->nr_targets;
+- }
++ rc = cifs_wait_for_server_reconnect(server, tcon->retry);
++ if (rc)
++ return rc;
+
+ spin_lock(&ses->chan_lock);
+ if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
+@@ -4356,8 +4319,13 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
+ return -ENODEV;
+
+ getDFSRetry:
+- rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
+- (void **) &pSMBr);
++ /*
++ * Use smb_init_no_reconnect() instead of smb_init() as
++ * CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus
++ * causing an infinite recursion.
++ */
++ rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
++ (void **)&pSMB, (void **)&pSMBr);
+ if (rc)
+ return rc;
+
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index 7aecb1646b6fc..077c88c49dfdf 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -261,31 +261,42 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
+ cifs_chan_update_iface(ses, server);
+
+ spin_lock(&ses->chan_lock);
+- if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
+- goto next_session;
++ if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) {
++ spin_unlock(&ses->chan_lock);
++ continue;
++ }
+
+ if (mark_smb_session)
+ CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses);
+ else
+ cifs_chan_set_need_reconnect(ses, server);
+
++ cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
++ __func__, ses->chans_need_reconnect);
++
+ /* If all channels need reconnect, then tcon needs reconnect */
+- if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
+- goto next_session;
++ if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
++ spin_unlock(&ses->chan_lock);
++ continue;
++ }
++ spin_unlock(&ses->chan_lock);
+
++ spin_lock(&ses->ses_lock);
+ ses->ses_status = SES_NEED_RECON;
++ spin_unlock(&ses->ses_lock);
+
+ list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
+ tcon->need_reconnect = true;
++ spin_lock(&tcon->tc_lock);
+ tcon->status = TID_NEED_RECON;
++ spin_unlock(&tcon->tc_lock);
+ }
+ if (ses->tcon_ipc) {
+ ses->tcon_ipc->need_reconnect = true;
++ spin_lock(&ses->tcon_ipc->tc_lock);
+ ses->tcon_ipc->status = TID_NEED_RECON;
++ spin_unlock(&ses->tcon_ipc->tc_lock);
+ }
+-
+-next_session:
+- spin_unlock(&ses->chan_lock);
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+ }
+@@ -4050,11 +4061,19 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
+
+ /* only send once per connect */
+ spin_lock(&server->srv_lock);
+- if (!server->ops->need_neg(server) ||
++ if (server->tcpStatus != CifsGood &&
++ server->tcpStatus != CifsNew &&
+ server->tcpStatus != CifsNeedNegotiate) {
++ spin_unlock(&server->srv_lock);
++ return -EHOSTDOWN;
++ }
++
++ if (!server->ops->need_neg(server) &&
++ server->tcpStatus == CifsGood) {
+ spin_unlock(&server->srv_lock);
+ return 0;
+ }
++
+ server->tcpStatus = CifsInNegotiate;
+ spin_unlock(&server->srv_lock);
+
+@@ -4082,39 +4101,48 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
+ struct nls_table *nls_info)
+ {
+ int rc = -ENOSYS;
+- struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
+- struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
++ struct TCP_Server_Info *pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server;
++ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&pserver->dstaddr;
++ struct sockaddr_in *addr = (struct sockaddr_in *)&pserver->dstaddr;
+ bool is_binding = false;
+
+ spin_lock(&ses->ses_lock);
+- if (server->dstaddr.ss_family == AF_INET6)
+- scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI6", &addr6->sin6_addr);
+- else
+- scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI4", &addr->sin_addr);
++ cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
++ __func__, ses->chans_need_reconnect);
+
+ if (ses->ses_status != SES_GOOD &&
+ ses->ses_status != SES_NEW &&
+ ses->ses_status != SES_NEED_RECON) {
+ spin_unlock(&ses->ses_lock);
+- return 0;
++ return -EHOSTDOWN;
+ }
+
+ /* only send once per connect */
+ spin_lock(&ses->chan_lock);
+- if (CIFS_ALL_CHANS_GOOD(ses) ||
+- cifs_chan_in_reconnect(ses, server)) {
++ if (CIFS_ALL_CHANS_GOOD(ses)) {
++ if (ses->ses_status == SES_NEED_RECON)
++ ses->ses_status = SES_GOOD;
+ spin_unlock(&ses->chan_lock);
+ spin_unlock(&ses->ses_lock);
+ return 0;
+ }
+- is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
++
+ cifs_chan_set_in_reconnect(ses, server);
++ is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+ spin_unlock(&ses->chan_lock);
+
+ if (!is_binding)
+ ses->ses_status = SES_IN_SETUP;
+ spin_unlock(&ses->ses_lock);
+
++ /* update ses ip_addr only for primary chan */
++ if (server == pserver) {
++ if (server->dstaddr.ss_family == AF_INET6)
++ scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI6", &addr6->sin6_addr);
++ else
++ scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI4", &addr->sin_addr);
++ }
++
+ if (!is_binding) {
+ ses->capabilities = server->capabilities;
+ if (!linuxExtEnabled)
+diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
+index 4e54736a06996..832856aef4b7a 100644
+--- a/fs/cifs/misc.c
++++ b/fs/cifs/misc.c
+@@ -1382,3 +1382,47 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid,
+ return 0;
+ }
+ #endif
++
++int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry)
++{
++ int timeout = 10;
++ int rc;
++
++ spin_lock(&server->srv_lock);
++ if (server->tcpStatus != CifsNeedReconnect) {
++ spin_unlock(&server->srv_lock);
++ return 0;
++ }
++ timeout *= server->nr_targets;
++ spin_unlock(&server->srv_lock);
++
++ /*
++ * Give demultiplex thread up to 10 seconds to each target available for
++ * reconnect -- should be greater than cifs socket timeout which is 7
++ * seconds.
++ *
++ * On "soft" mounts we wait once. Hard mounts keep retrying until
++ * process is killed or server comes back on-line.
++ */
++ do {
++ rc = wait_event_interruptible_timeout(server->response_q,
++ (server->tcpStatus != CifsNeedReconnect),
++ timeout * HZ);
++ if (rc < 0) {
++ cifs_dbg(FYI, "%s: aborting reconnect due to received signal\n",
++ __func__);
++ return -ERESTARTSYS;
++ }
++
++ /* are we still trying to reconnect? */
++ spin_lock(&server->srv_lock);
++ if (server->tcpStatus != CifsNeedReconnect) {
++ spin_unlock(&server->srv_lock);
++ return 0;
++ }
++ spin_unlock(&server->srv_lock);
++ } while (retry);
++
++ cifs_dbg(FYI, "%s: gave up waiting on reconnect\n", __func__);
++ return -EHOSTDOWN;
++}
+diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
+index 6e6e44d8b4c79..b37379b62cc77 100644
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -139,72 +139,12 @@ out:
+ return;
+ }
+
+-static int wait_for_server_reconnect(struct TCP_Server_Info *server,
+- __le16 smb2_command, bool retry)
+-{
+- int timeout = 10;
+- int rc;
+-
+- spin_lock(&server->srv_lock);
+- if (server->tcpStatus != CifsNeedReconnect) {
+- spin_unlock(&server->srv_lock);
+- return 0;
+- }
+- timeout *= server->nr_targets;
+- spin_unlock(&server->srv_lock);
+-
+- /*
+- * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
+- * here since they are implicitly done when session drops.
+- */
+- switch (smb2_command) {
+- /*
+- * BB Should we keep oplock break and add flush to exceptions?
+- */
+- case SMB2_TREE_DISCONNECT:
+- case SMB2_CANCEL:
+- case SMB2_CLOSE:
+- case SMB2_OPLOCK_BREAK:
+- return -EAGAIN;
+- }
+-
+- /*
+- * Give demultiplex thread up to 10 seconds to each target available for
+- * reconnect -- should be greater than cifs socket timeout which is 7
+- * seconds.
+- *
+- * On "soft" mounts we wait once. Hard mounts keep retrying until
+- * process is killed or server comes back on-line.
+- */
+- do {
+- rc = wait_event_interruptible_timeout(server->response_q,
+- (server->tcpStatus != CifsNeedReconnect),
+- timeout * HZ);
+- if (rc < 0) {
+- cifs_dbg(FYI, "%s: aborting reconnect due to received signal\n",
+- __func__);
+- return -ERESTARTSYS;
+- }
+-
+- /* are we still trying to reconnect? */
+- spin_lock(&server->srv_lock);
+- if (server->tcpStatus != CifsNeedReconnect) {
+- spin_unlock(&server->srv_lock);
+- return 0;
+- }
+- spin_unlock(&server->srv_lock);
+- } while (retry);
+-
+- cifs_dbg(FYI, "%s: gave up waiting on reconnect\n", __func__);
+- return -EHOSTDOWN;
+-}
+-
+ static int
+ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ struct TCP_Server_Info *server)
+ {
+ int rc = 0;
+- struct nls_table *nls_codepage;
++ struct nls_table *nls_codepage = NULL;
+ struct cifs_ses *ses;
+
+ /*
+@@ -239,7 +179,28 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ (!tcon->ses->server) || !server)
+ return -EIO;
+
+- rc = wait_for_server_reconnect(server, smb2_command, tcon->retry);
++ spin_lock(&server->srv_lock);
++ if (server->tcpStatus == CifsNeedReconnect) {
++ /*
++ * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
++ * here since they are implicitly done when session drops.
++ */
++ switch (smb2_command) {
++ /*
++ * BB Should we keep oplock break and add flush to exceptions?
++ */
++ case SMB2_TREE_DISCONNECT:
++ case SMB2_CANCEL:
++ case SMB2_CLOSE:
++ case SMB2_OPLOCK_BREAK:
++ spin_unlock(&server->srv_lock);
++ return -EAGAIN;
++ }
++ }
++ spin_unlock(&server->srv_lock);
++
++again:
++ rc = cifs_wait_for_server_reconnect(server, tcon->retry);
+ if (rc)
+ return rc;
+
+@@ -255,8 +216,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ tcon->ses->chans_need_reconnect,
+ tcon->need_reconnect);
+
+- nls_codepage = load_nls_default();
+-
++ mutex_lock(&ses->session_mutex);
+ /*
+ * Recheck after acquire mutex. If another thread is negotiating
+ * and the server never sends an answer the socket will be closed
+@@ -265,28 +225,38 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ spin_lock(&server->srv_lock);
+ if (server->tcpStatus == CifsNeedReconnect) {
+ spin_unlock(&server->srv_lock);
++ mutex_unlock(&ses->session_mutex);
++
++ if (tcon->retry)
++ goto again;
++
+ rc = -EHOSTDOWN;
+ goto out;
+ }
+ spin_unlock(&server->srv_lock);
+
++ nls_codepage = load_nls_default();
++
+ /*
+ * need to prevent multiple threads trying to simultaneously
+ * reconnect the same SMB session
+ */
++ spin_lock(&ses->ses_lock);
+ spin_lock(&ses->chan_lock);
+- if (!cifs_chan_needs_reconnect(ses, server)) {
++ if (!cifs_chan_needs_reconnect(ses, server) &&
++ ses->ses_status == SES_GOOD) {
+ spin_unlock(&ses->chan_lock);
+-
++ spin_unlock(&ses->ses_lock);
+ /* this means that we only need to tree connect */
+ if (tcon->need_reconnect)
+ goto skip_sess_setup;
+
++ mutex_unlock(&ses->session_mutex);
+ goto out;
+ }
+ spin_unlock(&ses->chan_lock);
++ spin_unlock(&ses->ses_lock);
+
+- mutex_lock(&ses->session_mutex);
+ rc = cifs_negotiate_protocol(0, ses, server);
+ if (!rc) {
+ rc = cifs_setup_session(0, ses, server, nls_codepage);
+@@ -302,10 +272,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
+ mutex_unlock(&ses->session_mutex);
+ goto out;
+ }
+- mutex_unlock(&ses->session_mutex);
+
+ skip_sess_setup:
+- mutex_lock(&ses->session_mutex);
+ if (!tcon->need_reconnect) {
+ mutex_unlock(&ses->session_mutex);
+ goto out;
+@@ -320,7 +288,7 @@ skip_sess_setup:
+ cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
+ if (rc) {
+ /* If sess reconnected but tcon didn't, something strange ... */
+- pr_warn_once("reconnect tcon failed rc = %d\n", rc);
++ cifs_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
+ goto out;
+ }
+
+@@ -1292,9 +1260,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
+ if (rc)
+ return rc;
+
+- spin_lock(&ses->chan_lock);
+- is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+- spin_unlock(&ses->chan_lock);
++ spin_lock(&ses->ses_lock);
++ is_binding = (ses->ses_status == SES_GOOD);
++ spin_unlock(&ses->ses_lock);
+
+ if (is_binding) {
+ req->hdr.SessionId = cpu_to_le64(ses->Suid);
+@@ -1452,9 +1420,9 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
+ goto out_put_spnego_key;
+ }
+
+- spin_lock(&ses->chan_lock);
+- is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+- spin_unlock(&ses->chan_lock);
++ spin_lock(&ses->ses_lock);
++ is_binding = (ses->ses_status == SES_GOOD);
++ spin_unlock(&ses->ses_lock);
+
+ /* keep session key if binding */
+ if (!is_binding) {
+@@ -1578,9 +1546,9 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
+
+ cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
+
+- spin_lock(&ses->chan_lock);
+- is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+- spin_unlock(&ses->chan_lock);
++ spin_lock(&ses->ses_lock);
++ is_binding = (ses->ses_status == SES_GOOD);
++ spin_unlock(&ses->ses_lock);
+
+ /* keep existing ses id and flags if binding */
+ if (!is_binding) {
+@@ -1646,9 +1614,9 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
+
+ rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
+
+- spin_lock(&ses->chan_lock);
+- is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
+- spin_unlock(&ses->chan_lock);
++ spin_lock(&ses->ses_lock);
++ is_binding = (ses->ses_status == SES_GOOD);
++ spin_unlock(&ses->ses_lock);
+
+ /* keep existing ses id and flags if binding */
+ if (!is_binding) {
+diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
+index d827b7547ffad..790acf65a0926 100644
+--- a/fs/cifs/smb2transport.c
++++ b/fs/cifs/smb2transport.c
+@@ -81,6 +81,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
+ struct cifs_ses *ses = NULL;
+ int i;
+ int rc = 0;
++ bool is_binding = false;
+
+ spin_lock(&cifs_tcp_ses_lock);
+
+@@ -97,9 +98,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
+ goto out;
+
+ found:
++ spin_lock(&ses->ses_lock);
+ spin_lock(&ses->chan_lock);
+- if (cifs_chan_needs_reconnect(ses, server) &&
+- !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
++
++ is_binding = (cifs_chan_needs_reconnect(ses, server) &&
++ ses->ses_status == SES_GOOD);
++ if (is_binding) {
+ /*
+ * If we are in the process of binding a new channel
+ * to an existing session, use the master connection
+@@ -107,6 +111,7 @@ found:
+ */
+ memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
+ spin_unlock(&ses->chan_lock);
++ spin_unlock(&ses->ses_lock);
+ goto out;
+ }
+
+@@ -119,10 +124,12 @@ found:
+ if (chan->server == server) {
+ memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE);
+ spin_unlock(&ses->chan_lock);
++ spin_unlock(&ses->ses_lock);
+ goto out;
+ }
+ }
+ spin_unlock(&ses->chan_lock);
++ spin_unlock(&ses->ses_lock);
+
+ cifs_dbg(VFS,
+ "%s: Could not find channel signing key for session 0x%llx\n",
+@@ -392,11 +399,15 @@ generate_smb3signingkey(struct cifs_ses *ses,
+ bool is_binding = false;
+ int chan_index = 0;
+
++ spin_lock(&ses->ses_lock);
+ spin_lock(&ses->chan_lock);
+- is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
++ is_binding = (cifs_chan_needs_reconnect(ses, server) &&
++ ses->ses_status == SES_GOOD);
++
+ chan_index = cifs_ses_get_chan_index(ses, server);
+ /* TODO: introduce ref counting for channels when the can be freed */
+ spin_unlock(&ses->chan_lock);
++ spin_unlock(&ses->ses_lock);
+
+ /*
+ * All channels use the same encryption/decryption keys but
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index d70da78e698d2..70e76359909cc 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -1980,8 +1980,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
+ if (!data->rpc_done) {
+ if (data->rpc_status)
+ return ERR_PTR(data->rpc_status);
+- /* cached opens have already been processed */
+- goto update;
++ return nfs4_try_open_cached(data);
+ }
+
+ ret = nfs_refresh_inode(inode, &data->f_attr);
+@@ -1990,7 +1989,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
+
+ if (data->o_res.delegation_type != 0)
+ nfs4_opendata_check_deleg(data, state);
+-update:
++
+ if (!update_open_stateid(state, &data->o_res.stateid,
+ NULL, data->o_arg.fmode))
+ return ERR_PTR(-EAGAIN);
+diff --git a/fs/verity/enable.c b/fs/verity/enable.c
+index df6b499bf6a14..400c264bf8930 100644
+--- a/fs/verity/enable.c
++++ b/fs/verity/enable.c
+@@ -390,25 +390,27 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg)
+ goto out_drop_write;
+
+ err = enable_verity(filp, &arg);
+- if (err)
+- goto out_allow_write_access;
+
+ /*
+- * Some pages of the file may have been evicted from pagecache after
+- * being used in the Merkle tree construction, then read into pagecache
+- * again by another process reading from the file concurrently. Since
+- * these pages didn't undergo verification against the file digest which
+- * fs-verity now claims to be enforcing, we have to wipe the pagecache
+- * to ensure that all future reads are verified.
++ * We no longer drop the inode's pagecache after enabling verity. This
++ * used to be done to try to avoid a race condition where pages could be
++ * evicted after being used in the Merkle tree construction, then
++ * re-instantiated by a concurrent read. Such pages are unverified, and
++ * the backing storage could have filled them with different content, so
++ * they shouldn't be used to fulfill reads once verity is enabled.
++ *
++ * But, dropping the pagecache has a big performance impact, and it
++ * doesn't fully solve the race condition anyway. So for those reasons,
++ * and also because this race condition isn't very important relatively
++ * speaking (especially for small-ish files, where the chance of a page
++ * being used, evicted, *and* re-instantiated all while enabling verity
++ * is quite small), we no longer drop the inode's pagecache.
+ */
+- filemap_write_and_wait(inode->i_mapping);
+- invalidate_inode_pages2(inode->i_mapping);
+
+ /*
+ * allow_write_access() is needed to pair with deny_write_access().
+ * Regardless, the filesystem won't allow writing to verity files.
+ */
+-out_allow_write_access:
+ allow_write_access(filp);
+ out_drop_write:
+ mnt_drop_write_file(filp);
+diff --git a/fs/zonefs/Makefile b/fs/zonefs/Makefile
+index 9fe54f5319f22..645f7229de4a0 100644
+--- a/fs/zonefs/Makefile
++++ b/fs/zonefs/Makefile
+@@ -3,4 +3,4 @@ ccflags-y += -I$(src)
+
+ obj-$(CONFIG_ZONEFS_FS) += zonefs.o
+
+-zonefs-y := super.o sysfs.o
++zonefs-y := super.o file.o sysfs.o
+diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c
+new file mode 100644
+index 0000000000000..63cd50840419c
+--- /dev/null
++++ b/fs/zonefs/file.c
+@@ -0,0 +1,902 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Simple file system for zoned block devices exposing zones as files.
++ *
++ * Copyright (C) 2022 Western Digital Corporation or its affiliates.
++ */
++#include <linux/module.h>
++#include <linux/pagemap.h>
++#include <linux/iomap.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/blkdev.h>
++#include <linux/statfs.h>
++#include <linux/writeback.h>
++#include <linux/quotaops.h>
++#include <linux/seq_file.h>
++#include <linux/parser.h>
++#include <linux/uio.h>
++#include <linux/mman.h>
++#include <linux/sched/mm.h>
++#include <linux/task_io_accounting_ops.h>
++
++#include "zonefs.h"
++
++#include "trace.h"
++
++static int zonefs_read_iomap_begin(struct inode *inode, loff_t offset,
++ loff_t length, unsigned int flags,
++ struct iomap *iomap, struct iomap *srcmap)
++{
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ struct super_block *sb = inode->i_sb;
++ loff_t isize;
++
++ /*
++ * All blocks are always mapped below EOF. If reading past EOF,
++ * act as if there is a hole up to the file maximum size.
++ */
++ mutex_lock(&zi->i_truncate_mutex);
++ iomap->bdev = inode->i_sb->s_bdev;
++ iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
++ isize = i_size_read(inode);
++ if (iomap->offset >= isize) {
++ iomap->type = IOMAP_HOLE;
++ iomap->addr = IOMAP_NULL_ADDR;
++ iomap->length = length;
++ } else {
++ iomap->type = IOMAP_MAPPED;
++ iomap->addr = (z->z_sector << SECTOR_SHIFT) + iomap->offset;
++ iomap->length = isize - iomap->offset;
++ }
++ mutex_unlock(&zi->i_truncate_mutex);
++
++ trace_zonefs_iomap_begin(inode, iomap);
++
++ return 0;
++}
++
++static const struct iomap_ops zonefs_read_iomap_ops = {
++ .iomap_begin = zonefs_read_iomap_begin,
++};
++
++static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
++ loff_t length, unsigned int flags,
++ struct iomap *iomap, struct iomap *srcmap)
++{
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ struct super_block *sb = inode->i_sb;
++ loff_t isize;
++
++ /* All write I/Os should always be within the file maximum size */
++ if (WARN_ON_ONCE(offset + length > z->z_capacity))
++ return -EIO;
++
++ /*
++ * Sequential zones can only accept direct writes. This is already
++ * checked when writes are issued, so warn if we see a page writeback
++ * operation.
++ */
++ if (WARN_ON_ONCE(zonefs_zone_is_seq(z) && !(flags & IOMAP_DIRECT)))
++ return -EIO;
++
++ /*
++ * For conventional zones, all blocks are always mapped. For sequential
++ * zones, all blocks after always mapped below the inode size (zone
++ * write pointer) and unwriten beyond.
++ */
++ mutex_lock(&zi->i_truncate_mutex);
++ iomap->bdev = inode->i_sb->s_bdev;
++ iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
++ iomap->addr = (z->z_sector << SECTOR_SHIFT) + iomap->offset;
++ isize = i_size_read(inode);
++ if (iomap->offset >= isize) {
++ iomap->type = IOMAP_UNWRITTEN;
++ iomap->length = z->z_capacity - iomap->offset;
++ } else {
++ iomap->type = IOMAP_MAPPED;
++ iomap->length = isize - iomap->offset;
++ }
++ mutex_unlock(&zi->i_truncate_mutex);
++
++ trace_zonefs_iomap_begin(inode, iomap);
++
++ return 0;
++}
++
++static const struct iomap_ops zonefs_write_iomap_ops = {
++ .iomap_begin = zonefs_write_iomap_begin,
++};
++
++static int zonefs_read_folio(struct file *unused, struct folio *folio)
++{
++ return iomap_read_folio(folio, &zonefs_read_iomap_ops);
++}
++
++static void zonefs_readahead(struct readahead_control *rac)
++{
++ iomap_readahead(rac, &zonefs_read_iomap_ops);
++}
++
++/*
++ * Map blocks for page writeback. This is used only on conventional zone files,
++ * which implies that the page range can only be within the fixed inode size.
++ */
++static int zonefs_write_map_blocks(struct iomap_writepage_ctx *wpc,
++ struct inode *inode, loff_t offset)
++{
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++
++ if (WARN_ON_ONCE(zonefs_zone_is_seq(z)))
++ return -EIO;
++ if (WARN_ON_ONCE(offset >= i_size_read(inode)))
++ return -EIO;
++
++ /* If the mapping is already OK, nothing needs to be done */
++ if (offset >= wpc->iomap.offset &&
++ offset < wpc->iomap.offset + wpc->iomap.length)
++ return 0;
++
++ return zonefs_write_iomap_begin(inode, offset,
++ z->z_capacity - offset,
++ IOMAP_WRITE, &wpc->iomap, NULL);
++}
++
++static const struct iomap_writeback_ops zonefs_writeback_ops = {
++ .map_blocks = zonefs_write_map_blocks,
++};
++
++static int zonefs_writepages(struct address_space *mapping,
++ struct writeback_control *wbc)
++{
++ struct iomap_writepage_ctx wpc = { };
++
++ return iomap_writepages(mapping, wbc, &wpc, &zonefs_writeback_ops);
++}
++
++static int zonefs_swap_activate(struct swap_info_struct *sis,
++ struct file *swap_file, sector_t *span)
++{
++ struct inode *inode = file_inode(swap_file);
++
++ if (zonefs_inode_is_seq(inode)) {
++ zonefs_err(inode->i_sb,
++ "swap file: not a conventional zone file\n");
++ return -EINVAL;
++ }
++
++ return iomap_swapfile_activate(sis, swap_file, span,
++ &zonefs_read_iomap_ops);
++}
++
++const struct address_space_operations zonefs_file_aops = {
++ .read_folio = zonefs_read_folio,
++ .readahead = zonefs_readahead,
++ .writepages = zonefs_writepages,
++ .dirty_folio = filemap_dirty_folio,
++ .release_folio = iomap_release_folio,
++ .invalidate_folio = iomap_invalidate_folio,
++ .migrate_folio = filemap_migrate_folio,
++ .is_partially_uptodate = iomap_is_partially_uptodate,
++ .error_remove_page = generic_error_remove_page,
++ .direct_IO = noop_direct_IO,
++ .swap_activate = zonefs_swap_activate,
++};
++
++int zonefs_file_truncate(struct inode *inode, loff_t isize)
++{
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ loff_t old_isize;
++ enum req_op op;
++ int ret = 0;
++
++ /*
++ * Only sequential zone files can be truncated and truncation is allowed
++ * only down to a 0 size, which is equivalent to a zone reset, and to
++ * the maximum file size, which is equivalent to a zone finish.
++ */
++ if (!zonefs_zone_is_seq(z))
++ return -EPERM;
++
++ if (!isize)
++ op = REQ_OP_ZONE_RESET;
++ else if (isize == z->z_capacity)
++ op = REQ_OP_ZONE_FINISH;
++ else
++ return -EPERM;
++
++ inode_dio_wait(inode);
++
++ /* Serialize against page faults */
++ filemap_invalidate_lock(inode->i_mapping);
++
++ /* Serialize against zonefs_iomap_begin() */
++ mutex_lock(&zi->i_truncate_mutex);
++
++ old_isize = i_size_read(inode);
++ if (isize == old_isize)
++ goto unlock;
++
++ ret = zonefs_inode_zone_mgmt(inode, op);
++ if (ret)
++ goto unlock;
++
++ /*
++ * If the mount option ZONEFS_MNTOPT_EXPLICIT_OPEN is set,
++ * take care of open zones.
++ */
++ if (z->z_flags & ZONEFS_ZONE_OPEN) {
++ /*
++ * Truncating a zone to EMPTY or FULL is the equivalent of
++ * closing the zone. For a truncation to 0, we need to
++ * re-open the zone to ensure new writes can be processed.
++ * For a truncation to the maximum file size, the zone is
++ * closed and writes cannot be accepted anymore, so clear
++ * the open flag.
++ */
++ if (!isize)
++ ret = zonefs_inode_zone_mgmt(inode, REQ_OP_ZONE_OPEN);
++ else
++ z->z_flags &= ~ZONEFS_ZONE_OPEN;
++ }
++
++ zonefs_update_stats(inode, isize);
++ truncate_setsize(inode, isize);
++ z->z_wpoffset = isize;
++ zonefs_inode_account_active(inode);
++
++unlock:
++ mutex_unlock(&zi->i_truncate_mutex);
++ filemap_invalidate_unlock(inode->i_mapping);
++
++ return ret;
++}
++
++static int zonefs_file_fsync(struct file *file, loff_t start, loff_t end,
++ int datasync)
++{
++ struct inode *inode = file_inode(file);
++ int ret = 0;
++
++ if (unlikely(IS_IMMUTABLE(inode)))
++ return -EPERM;
++
++ /*
++ * Since only direct writes are allowed in sequential files, page cache
++ * flush is needed only for conventional zone files.
++ */
++ if (zonefs_inode_is_cnv(inode))
++ ret = file_write_and_wait_range(file, start, end);
++ if (!ret)
++ ret = blkdev_issue_flush(inode->i_sb->s_bdev);
++
++ if (ret)
++ zonefs_io_error(inode, true);
++
++ return ret;
++}
++
++static vm_fault_t zonefs_filemap_page_mkwrite(struct vm_fault *vmf)
++{
++ struct inode *inode = file_inode(vmf->vma->vm_file);
++ vm_fault_t ret;
++
++ if (unlikely(IS_IMMUTABLE(inode)))
++ return VM_FAULT_SIGBUS;
++
++ /*
++ * Sanity check: only conventional zone files can have shared
++ * writeable mappings.
++ */
++ if (zonefs_inode_is_seq(inode))
++ return VM_FAULT_NOPAGE;
++
++ sb_start_pagefault(inode->i_sb);
++ file_update_time(vmf->vma->vm_file);
++
++ /* Serialize against truncates */
++ filemap_invalidate_lock_shared(inode->i_mapping);
++ ret = iomap_page_mkwrite(vmf, &zonefs_write_iomap_ops);
++ filemap_invalidate_unlock_shared(inode->i_mapping);
++
++ sb_end_pagefault(inode->i_sb);
++ return ret;
++}
++
++static const struct vm_operations_struct zonefs_file_vm_ops = {
++ .fault = filemap_fault,
++ .map_pages = filemap_map_pages,
++ .page_mkwrite = zonefs_filemap_page_mkwrite,
++};
++
++static int zonefs_file_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ /*
++ * Conventional zones accept random writes, so their files can support
++ * shared writable mappings. For sequential zone files, only read
++ * mappings are possible since there are no guarantees for write
++ * ordering between msync() and page cache writeback.
++ */
++ if (zonefs_inode_is_seq(file_inode(file)) &&
++ (vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
++ return -EINVAL;
++
++ file_accessed(file);
++ vma->vm_ops = &zonefs_file_vm_ops;
++
++ return 0;
++}
++
++static loff_t zonefs_file_llseek(struct file *file, loff_t offset, int whence)
++{
++ loff_t isize = i_size_read(file_inode(file));
++
++ /*
++ * Seeks are limited to below the zone size for conventional zones
++ * and below the zone write pointer for sequential zones. In both
++ * cases, this limit is the inode size.
++ */
++ return generic_file_llseek_size(file, offset, whence, isize, isize);
++}
++
++static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
++ int error, unsigned int flags)
++{
++ struct inode *inode = file_inode(iocb->ki_filp);
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++
++ if (error) {
++ zonefs_io_error(inode, true);
++ return error;
++ }
++
++ if (size && zonefs_inode_is_seq(inode)) {
++ /*
++ * Note that we may be seeing completions out of order,
++ * but that is not a problem since a write completed
++ * successfully necessarily means that all preceding writes
++ * were also successful. So we can safely increase the inode
++ * size to the write end location.
++ */
++ mutex_lock(&zi->i_truncate_mutex);
++ if (i_size_read(inode) < iocb->ki_pos + size) {
++ zonefs_update_stats(inode, iocb->ki_pos + size);
++ zonefs_i_size_write(inode, iocb->ki_pos + size);
++ }
++ mutex_unlock(&zi->i_truncate_mutex);
++ }
++
++ return 0;
++}
++
++static const struct iomap_dio_ops zonefs_write_dio_ops = {
++ .end_io = zonefs_file_write_dio_end_io,
++};
++
++static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
++{
++ struct inode *inode = file_inode(iocb->ki_filp);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ struct block_device *bdev = inode->i_sb->s_bdev;
++ unsigned int max = bdev_max_zone_append_sectors(bdev);
++ pgoff_t start, end;
++ struct bio *bio;
++ ssize_t size;
++ int nr_pages;
++ ssize_t ret;
++
++ max = ALIGN_DOWN(max << SECTOR_SHIFT, inode->i_sb->s_blocksize);
++ iov_iter_truncate(from, max);
++
++ /*
++ * If the inode block size (zone write granularity) is smaller than the
++ * page size, we may be appending data belonging to the last page of the
++ * inode straddling inode->i_size, with that page already cached due to
++ * a buffered read or readahead. So make sure to invalidate that page.
++ * This will always be a no-op for the case where the block size is
++ * equal to the page size.
++ */
++ start = iocb->ki_pos >> PAGE_SHIFT;
++ end = (iocb->ki_pos + iov_iter_count(from) - 1) >> PAGE_SHIFT;
++ if (invalidate_inode_pages2_range(inode->i_mapping, start, end))
++ return -EBUSY;
++
++ nr_pages = iov_iter_npages(from, BIO_MAX_VECS);
++ if (!nr_pages)
++ return 0;
++
++ bio = bio_alloc(bdev, nr_pages,
++ REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE, GFP_NOFS);
++ bio->bi_iter.bi_sector = z->z_sector;
++ bio->bi_ioprio = iocb->ki_ioprio;
++ if (iocb_is_dsync(iocb))
++ bio->bi_opf |= REQ_FUA;
++
++ ret = bio_iov_iter_get_pages(bio, from);
++ if (unlikely(ret))
++ goto out_release;
++
++ size = bio->bi_iter.bi_size;
++ task_io_account_write(size);
++
++ if (iocb->ki_flags & IOCB_HIPRI)
++ bio_set_polled(bio, iocb);
++
++ ret = submit_bio_wait(bio);
++
++ /*
++ * If the file zone was written underneath the file system, the zone
++ * write pointer may not be where we expect it to be, but the zone
++ * append write can still succeed. So check manually that we wrote where
++ * we intended to, that is, at zi->i_wpoffset.
++ */
++ if (!ret) {
++ sector_t wpsector =
++ z->z_sector + (z->z_wpoffset >> SECTOR_SHIFT);
++
++ if (bio->bi_iter.bi_sector != wpsector) {
++ zonefs_warn(inode->i_sb,
++ "Corrupted write pointer %llu for zone at %llu\n",
++ bio->bi_iter.bi_sector, z->z_sector);
++ ret = -EIO;
++ }
++ }
++
++ zonefs_file_write_dio_end_io(iocb, size, ret, 0);
++ trace_zonefs_file_dio_append(inode, size, ret);
++
++out_release:
++ bio_release_pages(bio, false);
++ bio_put(bio);
++
++ if (ret >= 0) {
++ iocb->ki_pos += size;
++ return size;
++ }
++
++ return ret;
++}
++
++/*
++ * Do not exceed the LFS limits nor the file zone size. If pos is under the
++ * limit it becomes a short access. If it exceeds the limit, return -EFBIG.
++ */
++static loff_t zonefs_write_check_limits(struct file *file, loff_t pos,
++ loff_t count)
++{
++ struct inode *inode = file_inode(file);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ loff_t limit = rlimit(RLIMIT_FSIZE);
++ loff_t max_size = z->z_capacity;
++
++ if (limit != RLIM_INFINITY) {
++ if (pos >= limit) {
++ send_sig(SIGXFSZ, current, 0);
++ return -EFBIG;
++ }
++ count = min(count, limit - pos);
++ }
++
++ if (!(file->f_flags & O_LARGEFILE))
++ max_size = min_t(loff_t, MAX_NON_LFS, max_size);
++
++ if (unlikely(pos >= max_size))
++ return -EFBIG;
++
++ return min(count, max_size - pos);
++}
++
++static ssize_t zonefs_write_checks(struct kiocb *iocb, struct iov_iter *from)
++{
++ struct file *file = iocb->ki_filp;
++ struct inode *inode = file_inode(file);
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ loff_t count;
++
++ if (IS_SWAPFILE(inode))
++ return -ETXTBSY;
++
++ if (!iov_iter_count(from))
++ return 0;
++
++ if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
++ return -EINVAL;
++
++ if (iocb->ki_flags & IOCB_APPEND) {
++ if (zonefs_zone_is_cnv(z))
++ return -EINVAL;
++ mutex_lock(&zi->i_truncate_mutex);
++ iocb->ki_pos = z->z_wpoffset;
++ mutex_unlock(&zi->i_truncate_mutex);
++ }
++
++ count = zonefs_write_check_limits(file, iocb->ki_pos,
++ iov_iter_count(from));
++ if (count < 0)
++ return count;
++
++ iov_iter_truncate(from, count);
++ return iov_iter_count(from);
++}
++
++/*
++ * Handle direct writes. For sequential zone files, this is the only possible
++ * write path. For these files, check that the user is issuing writes
++ * sequentially from the end of the file. This code assumes that the block layer
++ * delivers write requests to the device in sequential order. This is always the
++ * case if a block IO scheduler implementing the ELEVATOR_F_ZBD_SEQ_WRITE
++ * elevator feature is being used (e.g. mq-deadline). The block layer always
++ * automatically select such an elevator for zoned block devices during the
++ * device initialization.
++ */
++static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
++{
++ struct inode *inode = file_inode(iocb->ki_filp);
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ struct super_block *sb = inode->i_sb;
++ bool sync = is_sync_kiocb(iocb);
++ bool append = false;
++ ssize_t ret, count;
++
++ /*
++ * For async direct IOs to sequential zone files, refuse IOCB_NOWAIT
++ * as this can cause write reordering (e.g. the first aio gets EAGAIN
++ * on the inode lock but the second goes through but is now unaligned).
++ */
++ if (zonefs_zone_is_seq(z) && !sync && (iocb->ki_flags & IOCB_NOWAIT))
++ return -EOPNOTSUPP;
++
++ if (iocb->ki_flags & IOCB_NOWAIT) {
++ if (!inode_trylock(inode))
++ return -EAGAIN;
++ } else {
++ inode_lock(inode);
++ }
++
++ count = zonefs_write_checks(iocb, from);
++ if (count <= 0) {
++ ret = count;
++ goto inode_unlock;
++ }
++
++ if ((iocb->ki_pos | count) & (sb->s_blocksize - 1)) {
++ ret = -EINVAL;
++ goto inode_unlock;
++ }
++
++ /* Enforce sequential writes (append only) in sequential zones */
++ if (zonefs_zone_is_seq(z)) {
++ mutex_lock(&zi->i_truncate_mutex);
++ if (iocb->ki_pos != z->z_wpoffset) {
++ mutex_unlock(&zi->i_truncate_mutex);
++ ret = -EINVAL;
++ goto inode_unlock;
++ }
++ mutex_unlock(&zi->i_truncate_mutex);
++ append = sync;
++ }
++
++ if (append) {
++ ret = zonefs_file_dio_append(iocb, from);
++ } else {
++ /*
++ * iomap_dio_rw() may return ENOTBLK if there was an issue with
++ * page invalidation. Overwrite that error code with EBUSY to
++ * be consistent with zonefs_file_dio_append() return value for
++ * similar issues.
++ */
++ ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
++ &zonefs_write_dio_ops, 0, NULL, 0);
++ if (ret == -ENOTBLK)
++ ret = -EBUSY;
++ }
++
++ if (zonefs_zone_is_seq(z) &&
++ (ret > 0 || ret == -EIOCBQUEUED)) {
++ if (ret > 0)
++ count = ret;
++
++ /*
++ * Update the zone write pointer offset assuming the write
++ * operation succeeded. If it did not, the error recovery path
++ * will correct it. Also do active seq file accounting.
++ */
++ mutex_lock(&zi->i_truncate_mutex);
++ z->z_wpoffset += count;
++ zonefs_inode_account_active(inode);
++ mutex_unlock(&zi->i_truncate_mutex);
++ }
++
++inode_unlock:
++ inode_unlock(inode);
++
++ return ret;
++}
++
++static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
++ struct iov_iter *from)
++{
++ struct inode *inode = file_inode(iocb->ki_filp);
++ ssize_t ret;
++
++ /*
++ * Direct IO writes are mandatory for sequential zone files so that the
++ * write IO issuing order is preserved.
++ */
++ if (zonefs_inode_is_seq(inode))
++ return -EIO;
++
++ if (iocb->ki_flags & IOCB_NOWAIT) {
++ if (!inode_trylock(inode))
++ return -EAGAIN;
++ } else {
++ inode_lock(inode);
++ }
++
++ ret = zonefs_write_checks(iocb, from);
++ if (ret <= 0)
++ goto inode_unlock;
++
++ ret = iomap_file_buffered_write(iocb, from, &zonefs_write_iomap_ops);
++ if (ret > 0)
++ iocb->ki_pos += ret;
++ else if (ret == -EIO)
++ zonefs_io_error(inode, true);
++
++inode_unlock:
++ inode_unlock(inode);
++ if (ret > 0)
++ ret = generic_write_sync(iocb, ret);
++
++ return ret;
++}
++
++static ssize_t zonefs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
++{
++ struct inode *inode = file_inode(iocb->ki_filp);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++
++ if (unlikely(IS_IMMUTABLE(inode)))
++ return -EPERM;
++
++ if (sb_rdonly(inode->i_sb))
++ return -EROFS;
++
++ /* Write operations beyond the zone capacity are not allowed */
++ if (iocb->ki_pos >= z->z_capacity)
++ return -EFBIG;
++
++ if (iocb->ki_flags & IOCB_DIRECT) {
++ ssize_t ret = zonefs_file_dio_write(iocb, from);
++
++ if (ret != -ENOTBLK)
++ return ret;
++ }
++
++ return zonefs_file_buffered_write(iocb, from);
++}
++
++static int zonefs_file_read_dio_end_io(struct kiocb *iocb, ssize_t size,
++ int error, unsigned int flags)
++{
++ if (error) {
++ zonefs_io_error(file_inode(iocb->ki_filp), false);
++ return error;
++ }
++
++ return 0;
++}
++
++static const struct iomap_dio_ops zonefs_read_dio_ops = {
++ .end_io = zonefs_file_read_dio_end_io,
++};
++
++static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
++{
++ struct inode *inode = file_inode(iocb->ki_filp);
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ struct super_block *sb = inode->i_sb;
++ loff_t isize;
++ ssize_t ret;
++
++ /* Offline zones cannot be read */
++ if (unlikely(IS_IMMUTABLE(inode) && !(inode->i_mode & 0777)))
++ return -EPERM;
++
++ if (iocb->ki_pos >= z->z_capacity)
++ return 0;
++
++ if (iocb->ki_flags & IOCB_NOWAIT) {
++ if (!inode_trylock_shared(inode))
++ return -EAGAIN;
++ } else {
++ inode_lock_shared(inode);
++ }
++
++ /* Limit read operations to written data */
++ mutex_lock(&zi->i_truncate_mutex);
++ isize = i_size_read(inode);
++ if (iocb->ki_pos >= isize) {
++ mutex_unlock(&zi->i_truncate_mutex);
++ ret = 0;
++ goto inode_unlock;
++ }
++ iov_iter_truncate(to, isize - iocb->ki_pos);
++ mutex_unlock(&zi->i_truncate_mutex);
++
++ if (iocb->ki_flags & IOCB_DIRECT) {
++ size_t count = iov_iter_count(to);
++
++ if ((iocb->ki_pos | count) & (sb->s_blocksize - 1)) {
++ ret = -EINVAL;
++ goto inode_unlock;
++ }
++ file_accessed(iocb->ki_filp);
++ ret = iomap_dio_rw(iocb, to, &zonefs_read_iomap_ops,
++ &zonefs_read_dio_ops, 0, NULL, 0);
++ } else {
++ ret = generic_file_read_iter(iocb, to);
++ if (ret == -EIO)
++ zonefs_io_error(inode, false);
++ }
++
++inode_unlock:
++ inode_unlock_shared(inode);
++
++ return ret;
++}
++
++/*
++ * Write open accounting is done only for sequential files.
++ */
++static inline bool zonefs_seq_file_need_wro(struct inode *inode,
++ struct file *file)
++{
++ if (zonefs_inode_is_cnv(inode))
++ return false;
++
++ if (!(file->f_mode & FMODE_WRITE))
++ return false;
++
++ return true;
++}
++
++static int zonefs_seq_file_write_open(struct inode *inode)
++{
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ int ret = 0;
++
++ mutex_lock(&zi->i_truncate_mutex);
++
++ if (!zi->i_wr_refcnt) {
++ struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
++ unsigned int wro = atomic_inc_return(&sbi->s_wro_seq_files);
++
++ if (sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) {
++
++ if (sbi->s_max_wro_seq_files
++ && wro > sbi->s_max_wro_seq_files) {
++ atomic_dec(&sbi->s_wro_seq_files);
++ ret = -EBUSY;
++ goto unlock;
++ }
++
++ if (i_size_read(inode) < z->z_capacity) {
++ ret = zonefs_inode_zone_mgmt(inode,
++ REQ_OP_ZONE_OPEN);
++ if (ret) {
++ atomic_dec(&sbi->s_wro_seq_files);
++ goto unlock;
++ }
++ z->z_flags |= ZONEFS_ZONE_OPEN;
++ zonefs_inode_account_active(inode);
++ }
++ }
++ }
++
++ zi->i_wr_refcnt++;
++
++unlock:
++ mutex_unlock(&zi->i_truncate_mutex);
++
++ return ret;
++}
++
++static int zonefs_file_open(struct inode *inode, struct file *file)
++{
++ int ret;
++
++ ret = generic_file_open(inode, file);
++ if (ret)
++ return ret;
++
++ if (zonefs_seq_file_need_wro(inode, file))
++ return zonefs_seq_file_write_open(inode);
++
++ return 0;
++}
++
++static void zonefs_seq_file_write_close(struct inode *inode)
++{
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++ struct super_block *sb = inode->i_sb;
++ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
++ int ret = 0;
++
++ mutex_lock(&zi->i_truncate_mutex);
++
++ zi->i_wr_refcnt--;
++ if (zi->i_wr_refcnt)
++ goto unlock;
++
++ /*
++ * The file zone may not be open anymore (e.g. the file was truncated to
++ * its maximum size or it was fully written). For this case, we only
++ * need to decrement the write open count.
++ */
++ if (z->z_flags & ZONEFS_ZONE_OPEN) {
++ ret = zonefs_inode_zone_mgmt(inode, REQ_OP_ZONE_CLOSE);
++ if (ret) {
++ __zonefs_io_error(inode, false);
++ /*
++ * Leaving zones explicitly open may lead to a state
++ * where most zones cannot be written (zone resources
++ * exhausted). So take preventive action by remounting
++ * read-only.
++ */
++ if (z->z_flags & ZONEFS_ZONE_OPEN &&
++ !(sb->s_flags & SB_RDONLY)) {
++ zonefs_warn(sb,
++ "closing zone at %llu failed %d\n",
++ z->z_sector, ret);
++ zonefs_warn(sb,
++ "remounting filesystem read-only\n");
++ sb->s_flags |= SB_RDONLY;
++ }
++ goto unlock;
++ }
++
++ z->z_flags &= ~ZONEFS_ZONE_OPEN;
++ zonefs_inode_account_active(inode);
++ }
++
++ atomic_dec(&sbi->s_wro_seq_files);
++
++unlock:
++ mutex_unlock(&zi->i_truncate_mutex);
++}
++
++static int zonefs_file_release(struct inode *inode, struct file *file)
++{
++ /*
++ * If we explicitly open a zone we must close it again as well, but the
++ * zone management operation can fail (either due to an IO error or as
++ * the zone has gone offline or read-only). Make sure we don't fail the
++ * close(2) for user-space.
++ */
++ if (zonefs_seq_file_need_wro(inode, file))
++ zonefs_seq_file_write_close(inode);
++
++ return 0;
++}
++
++const struct file_operations zonefs_file_operations = {
++ .open = zonefs_file_open,
++ .release = zonefs_file_release,
++ .fsync = zonefs_file_fsync,
++ .mmap = zonefs_file_mmap,
++ .llseek = zonefs_file_llseek,
++ .read_iter = zonefs_file_read_iter,
++ .write_iter = zonefs_file_write_iter,
++ .splice_read = generic_file_splice_read,
++ .splice_write = iter_file_splice_write,
++ .iopoll = iocb_bio_iopoll,
++};
+diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
+index a9c5c3f720adf..270ded209dde5 100644
+--- a/fs/zonefs/super.c
++++ b/fs/zonefs/super.c
+@@ -28,33 +28,47 @@
+ #include "trace.h"
+
+ /*
+- * Manage the active zone count. Called with zi->i_truncate_mutex held.
++ * Get the name of a zone group directory.
+ */
+-static void zonefs_account_active(struct inode *inode)
++static const char *zonefs_zgroup_name(enum zonefs_ztype ztype)
+ {
+- struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ switch (ztype) {
++ case ZONEFS_ZTYPE_CNV:
++ return "cnv";
++ case ZONEFS_ZTYPE_SEQ:
++ return "seq";
++ default:
++ WARN_ON_ONCE(1);
++ return "???";
++ }
++}
+
+- lockdep_assert_held(&zi->i_truncate_mutex);
++/*
++ * Manage the active zone count.
++ */
++static void zonefs_account_active(struct super_block *sb,
++ struct zonefs_zone *z)
++{
++ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
+
+- if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
++ if (zonefs_zone_is_cnv(z))
+ return;
+
+ /*
+ * For zones that transitioned to the offline or readonly condition,
+ * we only need to clear the active state.
+ */
+- if (zi->i_flags & (ZONEFS_ZONE_OFFLINE | ZONEFS_ZONE_READONLY))
++ if (z->z_flags & (ZONEFS_ZONE_OFFLINE | ZONEFS_ZONE_READONLY))
+ goto out;
+
+ /*
+ * If the zone is active, that is, if it is explicitly open or
+ * partially written, check if it was already accounted as active.
+ */
+- if ((zi->i_flags & ZONEFS_ZONE_OPEN) ||
+- (zi->i_wpoffset > 0 && zi->i_wpoffset < zi->i_max_size)) {
+- if (!(zi->i_flags & ZONEFS_ZONE_ACTIVE)) {
+- zi->i_flags |= ZONEFS_ZONE_ACTIVE;
++ if ((z->z_flags & ZONEFS_ZONE_OPEN) ||
++ (z->z_wpoffset > 0 && z->z_wpoffset < z->z_capacity)) {
++ if (!(z->z_flags & ZONEFS_ZONE_ACTIVE)) {
++ z->z_flags |= ZONEFS_ZONE_ACTIVE;
+ atomic_inc(&sbi->s_active_seq_files);
+ }
+ return;
+@@ -62,18 +76,29 @@ static void zonefs_account_active(struct inode *inode)
+
+ out:
+ /* The zone is not active. If it was, update the active count */
+- if (zi->i_flags & ZONEFS_ZONE_ACTIVE) {
+- zi->i_flags &= ~ZONEFS_ZONE_ACTIVE;
++ if (z->z_flags & ZONEFS_ZONE_ACTIVE) {
++ z->z_flags &= ~ZONEFS_ZONE_ACTIVE;
+ atomic_dec(&sbi->s_active_seq_files);
+ }
+ }
+
+-static inline int zonefs_zone_mgmt(struct inode *inode, enum req_op op)
++/*
++ * Manage the active zone count. Called with zi->i_truncate_mutex held.
++ */
++void zonefs_inode_account_active(struct inode *inode)
+ {
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- int ret;
++ lockdep_assert_held(&ZONEFS_I(inode)->i_truncate_mutex);
+
+- lockdep_assert_held(&zi->i_truncate_mutex);
++ return zonefs_account_active(inode->i_sb, zonefs_inode_zone(inode));
++}
++
++/*
++ * Execute a zone management operation.
++ */
++static int zonefs_zone_mgmt(struct super_block *sb,
++ struct zonefs_zone *z, enum req_op op)
++{
++ int ret;
+
+ /*
+ * With ZNS drives, closing an explicitly open zone that has not been
+@@ -83,201 +108,49 @@ static inline int zonefs_zone_mgmt(struct inode *inode, enum req_op op)
+ * are exceeded, make sure that the zone does not remain active by
+ * resetting it.
+ */
+- if (op == REQ_OP_ZONE_CLOSE && !zi->i_wpoffset)
++ if (op == REQ_OP_ZONE_CLOSE && !z->z_wpoffset)
+ op = REQ_OP_ZONE_RESET;
+
+- trace_zonefs_zone_mgmt(inode, op);
+- ret = blkdev_zone_mgmt(inode->i_sb->s_bdev, op, zi->i_zsector,
+- zi->i_zone_size >> SECTOR_SHIFT, GFP_NOFS);
++ trace_zonefs_zone_mgmt(sb, z, op);
++ ret = blkdev_zone_mgmt(sb->s_bdev, op, z->z_sector,
++ z->z_size >> SECTOR_SHIFT, GFP_NOFS);
+ if (ret) {
+- zonefs_err(inode->i_sb,
++ zonefs_err(sb,
+ "Zone management operation %s at %llu failed %d\n",
+- blk_op_str(op), zi->i_zsector, ret);
++ blk_op_str(op), z->z_sector, ret);
+ return ret;
+ }
+
+ return 0;
+ }
+
+-static inline void zonefs_i_size_write(struct inode *inode, loff_t isize)
++int zonefs_inode_zone_mgmt(struct inode *inode, enum req_op op)
+ {
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ lockdep_assert_held(&ZONEFS_I(inode)->i_truncate_mutex);
+
+- i_size_write(inode, isize);
+- /*
+- * A full zone is no longer open/active and does not need
+- * explicit closing.
+- */
+- if (isize >= zi->i_max_size) {
+- struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
+-
+- if (zi->i_flags & ZONEFS_ZONE_ACTIVE)
+- atomic_dec(&sbi->s_active_seq_files);
+- zi->i_flags &= ~(ZONEFS_ZONE_OPEN | ZONEFS_ZONE_ACTIVE);
+- }
++ return zonefs_zone_mgmt(inode->i_sb, zonefs_inode_zone(inode), op);
+ }
+
+-static int zonefs_read_iomap_begin(struct inode *inode, loff_t offset,
+- loff_t length, unsigned int flags,
+- struct iomap *iomap, struct iomap *srcmap)
++void zonefs_i_size_write(struct inode *inode, loff_t isize)
+ {
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- struct super_block *sb = inode->i_sb;
+- loff_t isize;
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
+
+- /*
+- * All blocks are always mapped below EOF. If reading past EOF,
+- * act as if there is a hole up to the file maximum size.
+- */
+- mutex_lock(&zi->i_truncate_mutex);
+- iomap->bdev = inode->i_sb->s_bdev;
+- iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
+- isize = i_size_read(inode);
+- if (iomap->offset >= isize) {
+- iomap->type = IOMAP_HOLE;
+- iomap->addr = IOMAP_NULL_ADDR;
+- iomap->length = length;
+- } else {
+- iomap->type = IOMAP_MAPPED;
+- iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
+- iomap->length = isize - iomap->offset;
+- }
+- mutex_unlock(&zi->i_truncate_mutex);
+-
+- trace_zonefs_iomap_begin(inode, iomap);
+-
+- return 0;
+-}
+-
+-static const struct iomap_ops zonefs_read_iomap_ops = {
+- .iomap_begin = zonefs_read_iomap_begin,
+-};
+-
+-static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
+- loff_t length, unsigned int flags,
+- struct iomap *iomap, struct iomap *srcmap)
+-{
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- struct super_block *sb = inode->i_sb;
+- loff_t isize;
+-
+- /* All write I/Os should always be within the file maximum size */
+- if (WARN_ON_ONCE(offset + length > zi->i_max_size))
+- return -EIO;
+-
+- /*
+- * Sequential zones can only accept direct writes. This is already
+- * checked when writes are issued, so warn if we see a page writeback
+- * operation.
+- */
+- if (WARN_ON_ONCE(zi->i_ztype == ZONEFS_ZTYPE_SEQ &&
+- !(flags & IOMAP_DIRECT)))
+- return -EIO;
++ i_size_write(inode, isize);
+
+ /*
+- * For conventional zones, all blocks are always mapped. For sequential
+- * zones, all blocks after always mapped below the inode size (zone
+- * write pointer) and unwriten beyond.
++ * A full zone is no longer open/active and does not need
++ * explicit closing.
+ */
+- mutex_lock(&zi->i_truncate_mutex);
+- iomap->bdev = inode->i_sb->s_bdev;
+- iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
+- iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
+- isize = i_size_read(inode);
+- if (iomap->offset >= isize) {
+- iomap->type = IOMAP_UNWRITTEN;
+- iomap->length = zi->i_max_size - iomap->offset;
+- } else {
+- iomap->type = IOMAP_MAPPED;
+- iomap->length = isize - iomap->offset;
+- }
+- mutex_unlock(&zi->i_truncate_mutex);
+-
+- trace_zonefs_iomap_begin(inode, iomap);
+-
+- return 0;
+-}
+-
+-static const struct iomap_ops zonefs_write_iomap_ops = {
+- .iomap_begin = zonefs_write_iomap_begin,
+-};
+-
+-static int zonefs_read_folio(struct file *unused, struct folio *folio)
+-{
+- return iomap_read_folio(folio, &zonefs_read_iomap_ops);
+-}
+-
+-static void zonefs_readahead(struct readahead_control *rac)
+-{
+- iomap_readahead(rac, &zonefs_read_iomap_ops);
+-}
+-
+-/*
+- * Map blocks for page writeback. This is used only on conventional zone files,
+- * which implies that the page range can only be within the fixed inode size.
+- */
+-static int zonefs_write_map_blocks(struct iomap_writepage_ctx *wpc,
+- struct inode *inode, loff_t offset)
+-{
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+-
+- if (WARN_ON_ONCE(zi->i_ztype != ZONEFS_ZTYPE_CNV))
+- return -EIO;
+- if (WARN_ON_ONCE(offset >= i_size_read(inode)))
+- return -EIO;
+-
+- /* If the mapping is already OK, nothing needs to be done */
+- if (offset >= wpc->iomap.offset &&
+- offset < wpc->iomap.offset + wpc->iomap.length)
+- return 0;
+-
+- return zonefs_write_iomap_begin(inode, offset, zi->i_max_size - offset,
+- IOMAP_WRITE, &wpc->iomap, NULL);
+-}
+-
+-static const struct iomap_writeback_ops zonefs_writeback_ops = {
+- .map_blocks = zonefs_write_map_blocks,
+-};
+-
+-static int zonefs_writepages(struct address_space *mapping,
+- struct writeback_control *wbc)
+-{
+- struct iomap_writepage_ctx wpc = { };
+-
+- return iomap_writepages(mapping, wbc, &wpc, &zonefs_writeback_ops);
+-}
+-
+-static int zonefs_swap_activate(struct swap_info_struct *sis,
+- struct file *swap_file, sector_t *span)
+-{
+- struct inode *inode = file_inode(swap_file);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ if (isize >= z->z_capacity) {
++ struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
+
+- if (zi->i_ztype != ZONEFS_ZTYPE_CNV) {
+- zonefs_err(inode->i_sb,
+- "swap file: not a conventional zone file\n");
+- return -EINVAL;
++ if (z->z_flags & ZONEFS_ZONE_ACTIVE)
++ atomic_dec(&sbi->s_active_seq_files);
++ z->z_flags &= ~(ZONEFS_ZONE_OPEN | ZONEFS_ZONE_ACTIVE);
+ }
+-
+- return iomap_swapfile_activate(sis, swap_file, span,
+- &zonefs_read_iomap_ops);
+ }
+
+-static const struct address_space_operations zonefs_file_aops = {
+- .read_folio = zonefs_read_folio,
+- .readahead = zonefs_readahead,
+- .writepages = zonefs_writepages,
+- .dirty_folio = filemap_dirty_folio,
+- .release_folio = iomap_release_folio,
+- .invalidate_folio = iomap_invalidate_folio,
+- .migrate_folio = filemap_migrate_folio,
+- .is_partially_uptodate = iomap_is_partially_uptodate,
+- .error_remove_page = generic_error_remove_page,
+- .direct_IO = noop_direct_IO,
+- .swap_activate = zonefs_swap_activate,
+-};
+-
+-static void zonefs_update_stats(struct inode *inode, loff_t new_isize)
++void zonefs_update_stats(struct inode *inode, loff_t new_isize)
+ {
+ struct super_block *sb = inode->i_sb;
+ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
+@@ -310,63 +183,68 @@ static void zonefs_update_stats(struct inode *inode, loff_t new_isize)
+ }
+
+ /*
+- * Check a zone condition and adjust its file inode access permissions for
+- * offline and readonly zones. Return the inode size corresponding to the
+- * amount of readable data in the zone.
++ * Check a zone condition. Return the amount of written (and still readable)
++ * data in the zone.
+ */
+-static loff_t zonefs_check_zone_condition(struct inode *inode,
+- struct blk_zone *zone, bool warn,
+- bool mount)
++static loff_t zonefs_check_zone_condition(struct super_block *sb,
++ struct zonefs_zone *z,
++ struct blk_zone *zone)
+ {
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+-
+ switch (zone->cond) {
+ case BLK_ZONE_COND_OFFLINE:
+- /*
+- * Dead zone: make the inode immutable, disable all accesses
+- * and set the file size to 0 (zone wp set to zone start).
+- */
+- if (warn)
+- zonefs_warn(inode->i_sb, "inode %lu: offline zone\n",
+- inode->i_ino);
+- inode->i_flags |= S_IMMUTABLE;
+- inode->i_mode &= ~0777;
+- zone->wp = zone->start;
+- zi->i_flags |= ZONEFS_ZONE_OFFLINE;
++ zonefs_warn(sb, "Zone %llu: offline zone\n",
++ z->z_sector);
++ z->z_flags |= ZONEFS_ZONE_OFFLINE;
+ return 0;
+ case BLK_ZONE_COND_READONLY:
+ /*
+- * The write pointer of read-only zones is invalid. If such a
+- * zone is found during mount, the file size cannot be retrieved
+- * so we treat the zone as offline (mount == true case).
+- * Otherwise, keep the file size as it was when last updated
+- * so that the user can recover data. In both cases, writes are
+- * always disabled for the zone.
++ * The write pointer of read-only zones is invalid, so we cannot
++ * determine the zone wpoffset (inode size). We thus keep the
++ * zone wpoffset as is, which leads to an empty file
++ * (wpoffset == 0) on mount. For a runtime error, this keeps
++ * the inode size as it was when last updated so that the user
++ * can recover data.
+ */
+- if (warn)
+- zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
+- inode->i_ino);
+- inode->i_flags |= S_IMMUTABLE;
+- if (mount) {
+- zone->cond = BLK_ZONE_COND_OFFLINE;
+- inode->i_mode &= ~0777;
+- zone->wp = zone->start;
+- zi->i_flags |= ZONEFS_ZONE_OFFLINE;
+- return 0;
+- }
+- zi->i_flags |= ZONEFS_ZONE_READONLY;
+- inode->i_mode &= ~0222;
+- return i_size_read(inode);
++ zonefs_warn(sb, "Zone %llu: read-only zone\n",
++ z->z_sector);
++ z->z_flags |= ZONEFS_ZONE_READONLY;
++ if (zonefs_zone_is_cnv(z))
++ return z->z_capacity;
++ return z->z_wpoffset;
+ case BLK_ZONE_COND_FULL:
+ /* The write pointer of full zones is invalid. */
+- return zi->i_max_size;
++ return z->z_capacity;
+ default:
+- if (zi->i_ztype == ZONEFS_ZTYPE_CNV)
+- return zi->i_max_size;
++ if (zonefs_zone_is_cnv(z))
++ return z->z_capacity;
+ return (zone->wp - zone->start) << SECTOR_SHIFT;
+ }
+ }
+
++/*
++ * Check a zone condition and adjust its inode access permissions for
++ * offline and readonly zones.
++ */
++static void zonefs_inode_update_mode(struct inode *inode)
++{
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
++
++ if (z->z_flags & ZONEFS_ZONE_OFFLINE) {
++ /* Offline zones cannot be read nor written */
++ inode->i_flags |= S_IMMUTABLE;
++ inode->i_mode &= ~0777;
++ } else if (z->z_flags & ZONEFS_ZONE_READONLY) {
++ /* Readonly zones cannot be written */
++ inode->i_flags |= S_IMMUTABLE;
++ if (z->z_flags & ZONEFS_ZONE_INIT_MODE)
++ inode->i_mode &= ~0777;
++ else
++ inode->i_mode &= ~0222;
++ }
++
++ z->z_flags &= ~ZONEFS_ZONE_INIT_MODE;
++}
++
+ struct zonefs_ioerr_data {
+ struct inode *inode;
+ bool write;
+@@ -377,7 +255,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
+ {
+ struct zonefs_ioerr_data *err = data;
+ struct inode *inode = err->inode;
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
+ struct super_block *sb = inode->i_sb;
+ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
+ loff_t isize, data_size;
+@@ -388,10 +266,9 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
+ * as there is no inconsistency between the inode size and the amount of
+ * data writen in the zone (data_size).
+ */
+- data_size = zonefs_check_zone_condition(inode, zone, true, false);
++ data_size = zonefs_check_zone_condition(sb, z, zone);
+ isize = i_size_read(inode);
+- if (zone->cond != BLK_ZONE_COND_OFFLINE &&
+- zone->cond != BLK_ZONE_COND_READONLY &&
++ if (!(z->z_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) &&
+ !err->write && isize == data_size)
+ return 0;
+
+@@ -414,8 +291,9 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
+ * In all cases, warn about inode size inconsistency and handle the
+ * IO error according to the zone condition and to the mount options.
+ */
+- if (zi->i_ztype == ZONEFS_ZTYPE_SEQ && isize != data_size)
+- zonefs_warn(sb, "inode %lu: invalid size %lld (should be %lld)\n",
++ if (zonefs_zone_is_seq(z) && isize != data_size)
++ zonefs_warn(sb,
++ "inode %lu: invalid size %lld (should be %lld)\n",
+ inode->i_ino, isize, data_size);
+
+ /*
+@@ -424,24 +302,22 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
+ * zone condition to read-only and offline respectively, as if the
+ * condition was signaled by the hardware.
+ */
+- if (zone->cond == BLK_ZONE_COND_OFFLINE ||
+- sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL) {
++ if ((z->z_flags & ZONEFS_ZONE_OFFLINE) ||
++ (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL)) {
+ zonefs_warn(sb, "inode %lu: read/write access disabled\n",
+ inode->i_ino);
+- if (zone->cond != BLK_ZONE_COND_OFFLINE) {
+- zone->cond = BLK_ZONE_COND_OFFLINE;
+- data_size = zonefs_check_zone_condition(inode, zone,
+- false, false);
+- }
+- } else if (zone->cond == BLK_ZONE_COND_READONLY ||
+- sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO) {
++ if (!(z->z_flags & ZONEFS_ZONE_OFFLINE))
++ z->z_flags |= ZONEFS_ZONE_OFFLINE;
++ zonefs_inode_update_mode(inode);
++ data_size = 0;
++ } else if ((z->z_flags & ZONEFS_ZONE_READONLY) ||
++ (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO)) {
+ zonefs_warn(sb, "inode %lu: write access disabled\n",
+ inode->i_ino);
+- if (zone->cond != BLK_ZONE_COND_READONLY) {
+- zone->cond = BLK_ZONE_COND_READONLY;
+- data_size = zonefs_check_zone_condition(inode, zone,
+- false, false);
+- }
++ if (!(z->z_flags & ZONEFS_ZONE_READONLY))
++ z->z_flags |= ZONEFS_ZONE_READONLY;
++ zonefs_inode_update_mode(inode);
++ data_size = isize;
+ } else if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO &&
+ data_size > isize) {
+ /* Do not expose garbage data */
+@@ -455,9 +331,8 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
+ * close of the zone when the inode file is closed.
+ */
+ if ((sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) &&
+- (zone->cond == BLK_ZONE_COND_OFFLINE ||
+- zone->cond == BLK_ZONE_COND_READONLY))
+- zi->i_flags &= ~ZONEFS_ZONE_OPEN;
++ (z->z_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)))
++ z->z_flags &= ~ZONEFS_ZONE_OPEN;
+
+ /*
+ * If error=remount-ro was specified, any error result in remounting
+@@ -474,8 +349,8 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
+ */
+ zonefs_update_stats(inode, data_size);
+ zonefs_i_size_write(inode, data_size);
+- zi->i_wpoffset = data_size;
+- zonefs_account_active(inode);
++ z->z_wpoffset = data_size;
++ zonefs_inode_account_active(inode);
+
+ return 0;
+ }
+@@ -487,9 +362,9 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
+ * eventually correct the file size and zonefs inode write pointer offset
+ * (which can be out of sync with the drive due to partial write failures).
+ */
+-static void __zonefs_io_error(struct inode *inode, bool write)
++void __zonefs_io_error(struct inode *inode, bool write)
+ {
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
++ struct zonefs_zone *z = zonefs_inode_zone(inode);
+ struct super_block *sb = inode->i_sb;
+ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
+ unsigned int noio_flag;
+@@ -505,8 +380,8 @@ static void __zonefs_io_error(struct inode *inode, bool write)
+ * files with aggregated conventional zones, for which the inode zone
+ * size is always larger than the device zone size.
+ */
+- if (zi->i_zone_size > bdev_zone_sectors(sb->s_bdev))
+- nr_zones = zi->i_zone_size >>
++ if (z->z_size > bdev_zone_sectors(sb->s_bdev))
++ nr_zones = z->z_size >>
+ (sbi->s_zone_sectors_shift + SECTOR_SHIFT);
+
+ /*
+@@ -518,7 +393,7 @@ static void __zonefs_io_error(struct inode *inode, bool write)
+ * the GFP_NOIO context avoids both problems.
+ */
+ noio_flag = memalloc_noio_save();
+- ret = blkdev_report_zones(sb->s_bdev, zi->i_zsector, nr_zones,
++ ret = blkdev_report_zones(sb->s_bdev, z->z_sector, nr_zones,
+ zonefs_io_error_cb, &err);
+ if (ret != nr_zones)
+ zonefs_err(sb, "Get inode %lu zone information failed %d\n",
+@@ -526,749 +401,6 @@ static void __zonefs_io_error(struct inode *inode, bool write)
+ memalloc_noio_restore(noio_flag);
+ }
+
+-static void zonefs_io_error(struct inode *inode, bool write)
+-{
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+-
+- mutex_lock(&zi->i_truncate_mutex);
+- __zonefs_io_error(inode, write);
+- mutex_unlock(&zi->i_truncate_mutex);
+-}
+-
+-static int zonefs_file_truncate(struct inode *inode, loff_t isize)
+-{
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- loff_t old_isize;
+- enum req_op op;
+- int ret = 0;
+-
+- /*
+- * Only sequential zone files can be truncated and truncation is allowed
+- * only down to a 0 size, which is equivalent to a zone reset, and to
+- * the maximum file size, which is equivalent to a zone finish.
+- */
+- if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
+- return -EPERM;
+-
+- if (!isize)
+- op = REQ_OP_ZONE_RESET;
+- else if (isize == zi->i_max_size)
+- op = REQ_OP_ZONE_FINISH;
+- else
+- return -EPERM;
+-
+- inode_dio_wait(inode);
+-
+- /* Serialize against page faults */
+- filemap_invalidate_lock(inode->i_mapping);
+-
+- /* Serialize against zonefs_iomap_begin() */
+- mutex_lock(&zi->i_truncate_mutex);
+-
+- old_isize = i_size_read(inode);
+- if (isize == old_isize)
+- goto unlock;
+-
+- ret = zonefs_zone_mgmt(inode, op);
+- if (ret)
+- goto unlock;
+-
+- /*
+- * If the mount option ZONEFS_MNTOPT_EXPLICIT_OPEN is set,
+- * take care of open zones.
+- */
+- if (zi->i_flags & ZONEFS_ZONE_OPEN) {
+- /*
+- * Truncating a zone to EMPTY or FULL is the equivalent of
+- * closing the zone. For a truncation to 0, we need to
+- * re-open the zone to ensure new writes can be processed.
+- * For a truncation to the maximum file size, the zone is
+- * closed and writes cannot be accepted anymore, so clear
+- * the open flag.
+- */
+- if (!isize)
+- ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_OPEN);
+- else
+- zi->i_flags &= ~ZONEFS_ZONE_OPEN;
+- }
+-
+- zonefs_update_stats(inode, isize);
+- truncate_setsize(inode, isize);
+- zi->i_wpoffset = isize;
+- zonefs_account_active(inode);
+-
+-unlock:
+- mutex_unlock(&zi->i_truncate_mutex);
+- filemap_invalidate_unlock(inode->i_mapping);
+-
+- return ret;
+-}
+-
+-static int zonefs_inode_setattr(struct user_namespace *mnt_userns,
+- struct dentry *dentry, struct iattr *iattr)
+-{
+- struct inode *inode = d_inode(dentry);
+- int ret;
+-
+- if (unlikely(IS_IMMUTABLE(inode)))
+- return -EPERM;
+-
+- ret = setattr_prepare(&init_user_ns, dentry, iattr);
+- if (ret)
+- return ret;
+-
+- /*
+- * Since files and directories cannot be created nor deleted, do not
+- * allow setting any write attributes on the sub-directories grouping
+- * files by zone type.
+- */
+- if ((iattr->ia_valid & ATTR_MODE) && S_ISDIR(inode->i_mode) &&
+- (iattr->ia_mode & 0222))
+- return -EPERM;
+-
+- if (((iattr->ia_valid & ATTR_UID) &&
+- !uid_eq(iattr->ia_uid, inode->i_uid)) ||
+- ((iattr->ia_valid & ATTR_GID) &&
+- !gid_eq(iattr->ia_gid, inode->i_gid))) {
+- ret = dquot_transfer(mnt_userns, inode, iattr);
+- if (ret)
+- return ret;
+- }
+-
+- if (iattr->ia_valid & ATTR_SIZE) {
+- ret = zonefs_file_truncate(inode, iattr->ia_size);
+- if (ret)
+- return ret;
+- }
+-
+- setattr_copy(&init_user_ns, inode, iattr);
+-
+- return 0;
+-}
+-
+-static const struct inode_operations zonefs_file_inode_operations = {
+- .setattr = zonefs_inode_setattr,
+-};
+-
+-static int zonefs_file_fsync(struct file *file, loff_t start, loff_t end,
+- int datasync)
+-{
+- struct inode *inode = file_inode(file);
+- int ret = 0;
+-
+- if (unlikely(IS_IMMUTABLE(inode)))
+- return -EPERM;
+-
+- /*
+- * Since only direct writes are allowed in sequential files, page cache
+- * flush is needed only for conventional zone files.
+- */
+- if (ZONEFS_I(inode)->i_ztype == ZONEFS_ZTYPE_CNV)
+- ret = file_write_and_wait_range(file, start, end);
+- if (!ret)
+- ret = blkdev_issue_flush(inode->i_sb->s_bdev);
+-
+- if (ret)
+- zonefs_io_error(inode, true);
+-
+- return ret;
+-}
+-
+-static vm_fault_t zonefs_filemap_page_mkwrite(struct vm_fault *vmf)
+-{
+- struct inode *inode = file_inode(vmf->vma->vm_file);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- vm_fault_t ret;
+-
+- if (unlikely(IS_IMMUTABLE(inode)))
+- return VM_FAULT_SIGBUS;
+-
+- /*
+- * Sanity check: only conventional zone files can have shared
+- * writeable mappings.
+- */
+- if (WARN_ON_ONCE(zi->i_ztype != ZONEFS_ZTYPE_CNV))
+- return VM_FAULT_NOPAGE;
+-
+- sb_start_pagefault(inode->i_sb);
+- file_update_time(vmf->vma->vm_file);
+-
+- /* Serialize against truncates */
+- filemap_invalidate_lock_shared(inode->i_mapping);
+- ret = iomap_page_mkwrite(vmf, &zonefs_write_iomap_ops);
+- filemap_invalidate_unlock_shared(inode->i_mapping);
+-
+- sb_end_pagefault(inode->i_sb);
+- return ret;
+-}
+-
+-static const struct vm_operations_struct zonefs_file_vm_ops = {
+- .fault = filemap_fault,
+- .map_pages = filemap_map_pages,
+- .page_mkwrite = zonefs_filemap_page_mkwrite,
+-};
+-
+-static int zonefs_file_mmap(struct file *file, struct vm_area_struct *vma)
+-{
+- /*
+- * Conventional zones accept random writes, so their files can support
+- * shared writable mappings. For sequential zone files, only read
+- * mappings are possible since there are no guarantees for write
+- * ordering between msync() and page cache writeback.
+- */
+- if (ZONEFS_I(file_inode(file))->i_ztype == ZONEFS_ZTYPE_SEQ &&
+- (vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
+- return -EINVAL;
+-
+- file_accessed(file);
+- vma->vm_ops = &zonefs_file_vm_ops;
+-
+- return 0;
+-}
+-
+-static loff_t zonefs_file_llseek(struct file *file, loff_t offset, int whence)
+-{
+- loff_t isize = i_size_read(file_inode(file));
+-
+- /*
+- * Seeks are limited to below the zone size for conventional zones
+- * and below the zone write pointer for sequential zones. In both
+- * cases, this limit is the inode size.
+- */
+- return generic_file_llseek_size(file, offset, whence, isize, isize);
+-}
+-
+-static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
+- int error, unsigned int flags)
+-{
+- struct inode *inode = file_inode(iocb->ki_filp);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+-
+- if (error) {
+- zonefs_io_error(inode, true);
+- return error;
+- }
+-
+- if (size && zi->i_ztype != ZONEFS_ZTYPE_CNV) {
+- /*
+- * Note that we may be seeing completions out of order,
+- * but that is not a problem since a write completed
+- * successfully necessarily means that all preceding writes
+- * were also successful. So we can safely increase the inode
+- * size to the write end location.
+- */
+- mutex_lock(&zi->i_truncate_mutex);
+- if (i_size_read(inode) < iocb->ki_pos + size) {
+- zonefs_update_stats(inode, iocb->ki_pos + size);
+- zonefs_i_size_write(inode, iocb->ki_pos + size);
+- }
+- mutex_unlock(&zi->i_truncate_mutex);
+- }
+-
+- return 0;
+-}
+-
+-static const struct iomap_dio_ops zonefs_write_dio_ops = {
+- .end_io = zonefs_file_write_dio_end_io,
+-};
+-
+-static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
+-{
+- struct inode *inode = file_inode(iocb->ki_filp);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- struct block_device *bdev = inode->i_sb->s_bdev;
+- unsigned int max = bdev_max_zone_append_sectors(bdev);
+- struct bio *bio;
+- ssize_t size;
+- int nr_pages;
+- ssize_t ret;
+-
+- max = ALIGN_DOWN(max << SECTOR_SHIFT, inode->i_sb->s_blocksize);
+- iov_iter_truncate(from, max);
+-
+- nr_pages = iov_iter_npages(from, BIO_MAX_VECS);
+- if (!nr_pages)
+- return 0;
+-
+- bio = bio_alloc(bdev, nr_pages,
+- REQ_OP_ZONE_APPEND | REQ_SYNC | REQ_IDLE, GFP_NOFS);
+- bio->bi_iter.bi_sector = zi->i_zsector;
+- bio->bi_ioprio = iocb->ki_ioprio;
+- if (iocb_is_dsync(iocb))
+- bio->bi_opf |= REQ_FUA;
+-
+- ret = bio_iov_iter_get_pages(bio, from);
+- if (unlikely(ret))
+- goto out_release;
+-
+- size = bio->bi_iter.bi_size;
+- task_io_account_write(size);
+-
+- if (iocb->ki_flags & IOCB_HIPRI)
+- bio_set_polled(bio, iocb);
+-
+- ret = submit_bio_wait(bio);
+-
+- /*
+- * If the file zone was written underneath the file system, the zone
+- * write pointer may not be where we expect it to be, but the zone
+- * append write can still succeed. So check manually that we wrote where
+- * we intended to, that is, at zi->i_wpoffset.
+- */
+- if (!ret) {
+- sector_t wpsector =
+- zi->i_zsector + (zi->i_wpoffset >> SECTOR_SHIFT);
+-
+- if (bio->bi_iter.bi_sector != wpsector) {
+- zonefs_warn(inode->i_sb,
+- "Corrupted write pointer %llu for zone at %llu\n",
+- wpsector, zi->i_zsector);
+- ret = -EIO;
+- }
+- }
+-
+- zonefs_file_write_dio_end_io(iocb, size, ret, 0);
+- trace_zonefs_file_dio_append(inode, size, ret);
+-
+-out_release:
+- bio_release_pages(bio, false);
+- bio_put(bio);
+-
+- if (ret >= 0) {
+- iocb->ki_pos += size;
+- return size;
+- }
+-
+- return ret;
+-}
+-
+-/*
+- * Do not exceed the LFS limits nor the file zone size. If pos is under the
+- * limit it becomes a short access. If it exceeds the limit, return -EFBIG.
+- */
+-static loff_t zonefs_write_check_limits(struct file *file, loff_t pos,
+- loff_t count)
+-{
+- struct inode *inode = file_inode(file);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- loff_t limit = rlimit(RLIMIT_FSIZE);
+- loff_t max_size = zi->i_max_size;
+-
+- if (limit != RLIM_INFINITY) {
+- if (pos >= limit) {
+- send_sig(SIGXFSZ, current, 0);
+- return -EFBIG;
+- }
+- count = min(count, limit - pos);
+- }
+-
+- if (!(file->f_flags & O_LARGEFILE))
+- max_size = min_t(loff_t, MAX_NON_LFS, max_size);
+-
+- if (unlikely(pos >= max_size))
+- return -EFBIG;
+-
+- return min(count, max_size - pos);
+-}
+-
+-static ssize_t zonefs_write_checks(struct kiocb *iocb, struct iov_iter *from)
+-{
+- struct file *file = iocb->ki_filp;
+- struct inode *inode = file_inode(file);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- loff_t count;
+-
+- if (IS_SWAPFILE(inode))
+- return -ETXTBSY;
+-
+- if (!iov_iter_count(from))
+- return 0;
+-
+- if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
+- return -EINVAL;
+-
+- if (iocb->ki_flags & IOCB_APPEND) {
+- if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
+- return -EINVAL;
+- mutex_lock(&zi->i_truncate_mutex);
+- iocb->ki_pos = zi->i_wpoffset;
+- mutex_unlock(&zi->i_truncate_mutex);
+- }
+-
+- count = zonefs_write_check_limits(file, iocb->ki_pos,
+- iov_iter_count(from));
+- if (count < 0)
+- return count;
+-
+- iov_iter_truncate(from, count);
+- return iov_iter_count(from);
+-}
+-
+-/*
+- * Handle direct writes. For sequential zone files, this is the only possible
+- * write path. For these files, check that the user is issuing writes
+- * sequentially from the end of the file. This code assumes that the block layer
+- * delivers write requests to the device in sequential order. This is always the
+- * case if a block IO scheduler implementing the ELEVATOR_F_ZBD_SEQ_WRITE
+- * elevator feature is being used (e.g. mq-deadline). The block layer always
+- * automatically select such an elevator for zoned block devices during the
+- * device initialization.
+- */
+-static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
+-{
+- struct inode *inode = file_inode(iocb->ki_filp);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- struct super_block *sb = inode->i_sb;
+- bool sync = is_sync_kiocb(iocb);
+- bool append = false;
+- ssize_t ret, count;
+-
+- /*
+- * For async direct IOs to sequential zone files, refuse IOCB_NOWAIT
+- * as this can cause write reordering (e.g. the first aio gets EAGAIN
+- * on the inode lock but the second goes through but is now unaligned).
+- */
+- if (zi->i_ztype == ZONEFS_ZTYPE_SEQ && !sync &&
+- (iocb->ki_flags & IOCB_NOWAIT))
+- return -EOPNOTSUPP;
+-
+- if (iocb->ki_flags & IOCB_NOWAIT) {
+- if (!inode_trylock(inode))
+- return -EAGAIN;
+- } else {
+- inode_lock(inode);
+- }
+-
+- count = zonefs_write_checks(iocb, from);
+- if (count <= 0) {
+- ret = count;
+- goto inode_unlock;
+- }
+-
+- if ((iocb->ki_pos | count) & (sb->s_blocksize - 1)) {
+- ret = -EINVAL;
+- goto inode_unlock;
+- }
+-
+- /* Enforce sequential writes (append only) in sequential zones */
+- if (zi->i_ztype == ZONEFS_ZTYPE_SEQ) {
+- mutex_lock(&zi->i_truncate_mutex);
+- if (iocb->ki_pos != zi->i_wpoffset) {
+- mutex_unlock(&zi->i_truncate_mutex);
+- ret = -EINVAL;
+- goto inode_unlock;
+- }
+- mutex_unlock(&zi->i_truncate_mutex);
+- append = sync;
+- }
+-
+- if (append)
+- ret = zonefs_file_dio_append(iocb, from);
+- else
+- ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
+- &zonefs_write_dio_ops, 0, NULL, 0);
+- if (zi->i_ztype == ZONEFS_ZTYPE_SEQ &&
+- (ret > 0 || ret == -EIOCBQUEUED)) {
+- if (ret > 0)
+- count = ret;
+-
+- /*
+- * Update the zone write pointer offset assuming the write
+- * operation succeeded. If it did not, the error recovery path
+- * will correct it. Also do active seq file accounting.
+- */
+- mutex_lock(&zi->i_truncate_mutex);
+- zi->i_wpoffset += count;
+- zonefs_account_active(inode);
+- mutex_unlock(&zi->i_truncate_mutex);
+- }
+-
+-inode_unlock:
+- inode_unlock(inode);
+-
+- return ret;
+-}
+-
+-static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
+- struct iov_iter *from)
+-{
+- struct inode *inode = file_inode(iocb->ki_filp);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- ssize_t ret;
+-
+- /*
+- * Direct IO writes are mandatory for sequential zone files so that the
+- * write IO issuing order is preserved.
+- */
+- if (zi->i_ztype != ZONEFS_ZTYPE_CNV)
+- return -EIO;
+-
+- if (iocb->ki_flags & IOCB_NOWAIT) {
+- if (!inode_trylock(inode))
+- return -EAGAIN;
+- } else {
+- inode_lock(inode);
+- }
+-
+- ret = zonefs_write_checks(iocb, from);
+- if (ret <= 0)
+- goto inode_unlock;
+-
+- ret = iomap_file_buffered_write(iocb, from, &zonefs_write_iomap_ops);
+- if (ret > 0)
+- iocb->ki_pos += ret;
+- else if (ret == -EIO)
+- zonefs_io_error(inode, true);
+-
+-inode_unlock:
+- inode_unlock(inode);
+- if (ret > 0)
+- ret = generic_write_sync(iocb, ret);
+-
+- return ret;
+-}
+-
+-static ssize_t zonefs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
+-{
+- struct inode *inode = file_inode(iocb->ki_filp);
+-
+- if (unlikely(IS_IMMUTABLE(inode)))
+- return -EPERM;
+-
+- if (sb_rdonly(inode->i_sb))
+- return -EROFS;
+-
+- /* Write operations beyond the zone size are not allowed */
+- if (iocb->ki_pos >= ZONEFS_I(inode)->i_max_size)
+- return -EFBIG;
+-
+- if (iocb->ki_flags & IOCB_DIRECT) {
+- ssize_t ret = zonefs_file_dio_write(iocb, from);
+- if (ret != -ENOTBLK)
+- return ret;
+- }
+-
+- return zonefs_file_buffered_write(iocb, from);
+-}
+-
+-static int zonefs_file_read_dio_end_io(struct kiocb *iocb, ssize_t size,
+- int error, unsigned int flags)
+-{
+- if (error) {
+- zonefs_io_error(file_inode(iocb->ki_filp), false);
+- return error;
+- }
+-
+- return 0;
+-}
+-
+-static const struct iomap_dio_ops zonefs_read_dio_ops = {
+- .end_io = zonefs_file_read_dio_end_io,
+-};
+-
+-static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
+-{
+- struct inode *inode = file_inode(iocb->ki_filp);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- struct super_block *sb = inode->i_sb;
+- loff_t isize;
+- ssize_t ret;
+-
+- /* Offline zones cannot be read */
+- if (unlikely(IS_IMMUTABLE(inode) && !(inode->i_mode & 0777)))
+- return -EPERM;
+-
+- if (iocb->ki_pos >= zi->i_max_size)
+- return 0;
+-
+- if (iocb->ki_flags & IOCB_NOWAIT) {
+- if (!inode_trylock_shared(inode))
+- return -EAGAIN;
+- } else {
+- inode_lock_shared(inode);
+- }
+-
+- /* Limit read operations to written data */
+- mutex_lock(&zi->i_truncate_mutex);
+- isize = i_size_read(inode);
+- if (iocb->ki_pos >= isize) {
+- mutex_unlock(&zi->i_truncate_mutex);
+- ret = 0;
+- goto inode_unlock;
+- }
+- iov_iter_truncate(to, isize - iocb->ki_pos);
+- mutex_unlock(&zi->i_truncate_mutex);
+-
+- if (iocb->ki_flags & IOCB_DIRECT) {
+- size_t count = iov_iter_count(to);
+-
+- if ((iocb->ki_pos | count) & (sb->s_blocksize - 1)) {
+- ret = -EINVAL;
+- goto inode_unlock;
+- }
+- file_accessed(iocb->ki_filp);
+- ret = iomap_dio_rw(iocb, to, &zonefs_read_iomap_ops,
+- &zonefs_read_dio_ops, 0, NULL, 0);
+- } else {
+- ret = generic_file_read_iter(iocb, to);
+- if (ret == -EIO)
+- zonefs_io_error(inode, false);
+- }
+-
+-inode_unlock:
+- inode_unlock_shared(inode);
+-
+- return ret;
+-}
+-
+-/*
+- * Write open accounting is done only for sequential files.
+- */
+-static inline bool zonefs_seq_file_need_wro(struct inode *inode,
+- struct file *file)
+-{
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+-
+- if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
+- return false;
+-
+- if (!(file->f_mode & FMODE_WRITE))
+- return false;
+-
+- return true;
+-}
+-
+-static int zonefs_seq_file_write_open(struct inode *inode)
+-{
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- int ret = 0;
+-
+- mutex_lock(&zi->i_truncate_mutex);
+-
+- if (!zi->i_wr_refcnt) {
+- struct zonefs_sb_info *sbi = ZONEFS_SB(inode->i_sb);
+- unsigned int wro = atomic_inc_return(&sbi->s_wro_seq_files);
+-
+- if (sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) {
+-
+- if (sbi->s_max_wro_seq_files
+- && wro > sbi->s_max_wro_seq_files) {
+- atomic_dec(&sbi->s_wro_seq_files);
+- ret = -EBUSY;
+- goto unlock;
+- }
+-
+- if (i_size_read(inode) < zi->i_max_size) {
+- ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_OPEN);
+- if (ret) {
+- atomic_dec(&sbi->s_wro_seq_files);
+- goto unlock;
+- }
+- zi->i_flags |= ZONEFS_ZONE_OPEN;
+- zonefs_account_active(inode);
+- }
+- }
+- }
+-
+- zi->i_wr_refcnt++;
+-
+-unlock:
+- mutex_unlock(&zi->i_truncate_mutex);
+-
+- return ret;
+-}
+-
+-static int zonefs_file_open(struct inode *inode, struct file *file)
+-{
+- int ret;
+-
+- ret = generic_file_open(inode, file);
+- if (ret)
+- return ret;
+-
+- if (zonefs_seq_file_need_wro(inode, file))
+- return zonefs_seq_file_write_open(inode);
+-
+- return 0;
+-}
+-
+-static void zonefs_seq_file_write_close(struct inode *inode)
+-{
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- struct super_block *sb = inode->i_sb;
+- struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
+- int ret = 0;
+-
+- mutex_lock(&zi->i_truncate_mutex);
+-
+- zi->i_wr_refcnt--;
+- if (zi->i_wr_refcnt)
+- goto unlock;
+-
+- /*
+- * The file zone may not be open anymore (e.g. the file was truncated to
+- * its maximum size or it was fully written). For this case, we only
+- * need to decrement the write open count.
+- */
+- if (zi->i_flags & ZONEFS_ZONE_OPEN) {
+- ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_CLOSE);
+- if (ret) {
+- __zonefs_io_error(inode, false);
+- /*
+- * Leaving zones explicitly open may lead to a state
+- * where most zones cannot be written (zone resources
+- * exhausted). So take preventive action by remounting
+- * read-only.
+- */
+- if (zi->i_flags & ZONEFS_ZONE_OPEN &&
+- !(sb->s_flags & SB_RDONLY)) {
+- zonefs_warn(sb,
+- "closing zone at %llu failed %d\n",
+- zi->i_zsector, ret);
+- zonefs_warn(sb,
+- "remounting filesystem read-only\n");
+- sb->s_flags |= SB_RDONLY;
+- }
+- goto unlock;
+- }
+-
+- zi->i_flags &= ~ZONEFS_ZONE_OPEN;
+- zonefs_account_active(inode);
+- }
+-
+- atomic_dec(&sbi->s_wro_seq_files);
+-
+-unlock:
+- mutex_unlock(&zi->i_truncate_mutex);
+-}
+-
+-static int zonefs_file_release(struct inode *inode, struct file *file)
+-{
+- /*
+- * If we explicitly open a zone we must close it again as well, but the
+- * zone management operation can fail (either due to an IO error or as
+- * the zone has gone offline or read-only). Make sure we don't fail the
+- * close(2) for user-space.
+- */
+- if (zonefs_seq_file_need_wro(inode, file))
+- zonefs_seq_file_write_close(inode);
+-
+- return 0;
+-}
+-
+-static const struct file_operations zonefs_file_operations = {
+- .open = zonefs_file_open,
+- .release = zonefs_file_release,
+- .fsync = zonefs_file_fsync,
+- .mmap = zonefs_file_mmap,
+- .llseek = zonefs_file_llseek,
+- .read_iter = zonefs_file_read_iter,
+- .write_iter = zonefs_file_write_iter,
+- .splice_read = generic_file_splice_read,
+- .splice_write = iter_file_splice_write,
+- .iopoll = iocb_bio_iopoll,
+-};
+-
+ static struct kmem_cache *zonefs_inode_cachep;
+
+ static struct inode *zonefs_alloc_inode(struct super_block *sb)
+@@ -1282,7 +414,6 @@ static struct inode *zonefs_alloc_inode(struct super_block *sb)
+ inode_init_once(&zi->i_vnode);
+ mutex_init(&zi->i_truncate_mutex);
+ zi->i_wr_refcnt = 0;
+- zi->i_flags = 0;
+
+ return &zi->i_vnode;
+ }
+@@ -1315,8 +446,8 @@ static int zonefs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ buf->f_bavail = buf->f_bfree;
+
+ for (t = 0; t < ZONEFS_ZTYPE_MAX; t++) {
+- if (sbi->s_nr_files[t])
+- buf->f_files += sbi->s_nr_files[t] + 1;
++ if (sbi->s_zgroup[t].g_nr_zones)
++ buf->f_files += sbi->s_zgroup[t].g_nr_zones + 1;
+ }
+ buf->f_ffree = 0;
+
+@@ -1382,51 +513,85 @@ static int zonefs_parse_options(struct super_block *sb, char *options)
+ }
+ }
+
+- return 0;
+-}
++ return 0;
++}
++
++static int zonefs_show_options(struct seq_file *seq, struct dentry *root)
++{
++ struct zonefs_sb_info *sbi = ZONEFS_SB(root->d_sb);
++
++ if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO)
++ seq_puts(seq, ",errors=remount-ro");
++ if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO)
++ seq_puts(seq, ",errors=zone-ro");
++ if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL)
++ seq_puts(seq, ",errors=zone-offline");
++ if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_REPAIR)
++ seq_puts(seq, ",errors=repair");
++
++ return 0;
++}
++
++static int zonefs_remount(struct super_block *sb, int *flags, char *data)
++{
++ sync_filesystem(sb);
++
++ return zonefs_parse_options(sb, data);
++}
++
++static int zonefs_inode_setattr(struct user_namespace *mnt_userns,
++ struct dentry *dentry, struct iattr *iattr)
++{
++ struct inode *inode = d_inode(dentry);
++ int ret;
++
++ if (unlikely(IS_IMMUTABLE(inode)))
++ return -EPERM;
++
++ ret = setattr_prepare(&init_user_ns, dentry, iattr);
++ if (ret)
++ return ret;
++
++ /*
++ * Since files and directories cannot be created nor deleted, do not
++ * allow setting any write attributes on the sub-directories grouping
++ * files by zone type.
++ */
++ if ((iattr->ia_valid & ATTR_MODE) && S_ISDIR(inode->i_mode) &&
++ (iattr->ia_mode & 0222))
++ return -EPERM;
++
++ if (((iattr->ia_valid & ATTR_UID) &&
++ !uid_eq(iattr->ia_uid, inode->i_uid)) ||
++ ((iattr->ia_valid & ATTR_GID) &&
++ !gid_eq(iattr->ia_gid, inode->i_gid))) {
++ ret = dquot_transfer(mnt_userns, inode, iattr);
++ if (ret)
++ return ret;
++ }
+
+-static int zonefs_show_options(struct seq_file *seq, struct dentry *root)
+-{
+- struct zonefs_sb_info *sbi = ZONEFS_SB(root->d_sb);
++ if (iattr->ia_valid & ATTR_SIZE) {
++ ret = zonefs_file_truncate(inode, iattr->ia_size);
++ if (ret)
++ return ret;
++ }
+
+- if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO)
+- seq_puts(seq, ",errors=remount-ro");
+- if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO)
+- seq_puts(seq, ",errors=zone-ro");
+- if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL)
+- seq_puts(seq, ",errors=zone-offline");
+- if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_REPAIR)
+- seq_puts(seq, ",errors=repair");
++ setattr_copy(&init_user_ns, inode, iattr);
+
+ return 0;
+ }
+
+-static int zonefs_remount(struct super_block *sb, int *flags, char *data)
+-{
+- sync_filesystem(sb);
+-
+- return zonefs_parse_options(sb, data);
+-}
+-
+-static const struct super_operations zonefs_sops = {
+- .alloc_inode = zonefs_alloc_inode,
+- .free_inode = zonefs_free_inode,
+- .statfs = zonefs_statfs,
+- .remount_fs = zonefs_remount,
+- .show_options = zonefs_show_options,
+-};
+-
+ static const struct inode_operations zonefs_dir_inode_operations = {
+ .lookup = simple_lookup,
+ .setattr = zonefs_inode_setattr,
+ };
+
+ static void zonefs_init_dir_inode(struct inode *parent, struct inode *inode,
+- enum zonefs_ztype type)
++ enum zonefs_ztype ztype)
+ {
+ struct super_block *sb = parent->i_sb;
+
+- inode->i_ino = bdev_nr_zones(sb->s_bdev) + type + 1;
++ inode->i_ino = bdev_nr_zones(sb->s_bdev) + ztype + 1;
+ inode_init_owner(&init_user_ns, inode, parent, S_IFDIR | 0555);
+ inode->i_op = &zonefs_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+@@ -1434,73 +599,38 @@ static void zonefs_init_dir_inode(struct inode *parent, struct inode *inode,
+ inc_nlink(parent);
+ }
+
+-static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
+- enum zonefs_ztype type)
++static const struct inode_operations zonefs_file_inode_operations = {
++ .setattr = zonefs_inode_setattr,
++};
++
++static void zonefs_init_file_inode(struct inode *inode,
++ struct zonefs_zone *z)
+ {
+ struct super_block *sb = inode->i_sb;
+ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
+- struct zonefs_inode_info *zi = ZONEFS_I(inode);
+- int ret = 0;
+-
+- inode->i_ino = zone->start >> sbi->s_zone_sectors_shift;
+- inode->i_mode = S_IFREG | sbi->s_perm;
+-
+- zi->i_ztype = type;
+- zi->i_zsector = zone->start;
+- zi->i_zone_size = zone->len << SECTOR_SHIFT;
+- if (zi->i_zone_size > bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT &&
+- !(sbi->s_features & ZONEFS_F_AGGRCNV)) {
+- zonefs_err(sb,
+- "zone size %llu doesn't match device's zone sectors %llu\n",
+- zi->i_zone_size,
+- bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT);
+- return -EINVAL;
+- }
+
+- zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
+- zone->capacity << SECTOR_SHIFT);
+- zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true, true);
++ inode->i_private = z;
+
++ inode->i_ino = z->z_sector >> sbi->s_zone_sectors_shift;
++ inode->i_mode = S_IFREG | sbi->s_perm;
+ inode->i_uid = sbi->s_uid;
+ inode->i_gid = sbi->s_gid;
+- inode->i_size = zi->i_wpoffset;
+- inode->i_blocks = zi->i_max_size >> SECTOR_SHIFT;
++ inode->i_size = z->z_wpoffset;
++ inode->i_blocks = z->z_capacity >> SECTOR_SHIFT;
+
+ inode->i_op = &zonefs_file_inode_operations;
+ inode->i_fop = &zonefs_file_operations;
+ inode->i_mapping->a_ops = &zonefs_file_aops;
+
+- sb->s_maxbytes = max(zi->i_max_size, sb->s_maxbytes);
+- sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
+- sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits;
+-
+- mutex_lock(&zi->i_truncate_mutex);
+-
+- /*
+- * For sequential zones, make sure that any open zone is closed first
+- * to ensure that the initial number of open zones is 0, in sync with
+- * the open zone accounting done when the mount option
+- * ZONEFS_MNTOPT_EXPLICIT_OPEN is used.
+- */
+- if (type == ZONEFS_ZTYPE_SEQ &&
+- (zone->cond == BLK_ZONE_COND_IMP_OPEN ||
+- zone->cond == BLK_ZONE_COND_EXP_OPEN)) {
+- ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_CLOSE);
+- if (ret)
+- goto unlock;
+- }
+-
+- zonefs_account_active(inode);
+-
+-unlock:
+- mutex_unlock(&zi->i_truncate_mutex);
+-
+- return ret;
++ /* Update the inode access rights depending on the zone condition */
++ z->z_flags |= ZONEFS_ZONE_INIT_MODE;
++ zonefs_inode_update_mode(inode);
+ }
+
+ static struct dentry *zonefs_create_inode(struct dentry *parent,
+- const char *name, struct blk_zone *zone,
+- enum zonefs_ztype type)
++ const char *name,
++ struct zonefs_zone *z,
++ enum zonefs_ztype ztype)
+ {
+ struct inode *dir = d_inode(parent);
+ struct dentry *dentry;
+@@ -1516,15 +646,10 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
+ goto dput;
+
+ inode->i_ctime = inode->i_mtime = inode->i_atime = dir->i_ctime;
+- if (zone) {
+- ret = zonefs_init_file_inode(inode, zone, type);
+- if (ret) {
+- iput(inode);
+- goto dput;
+- }
+- } else {
+- zonefs_init_dir_inode(dir, inode, type);
+- }
++ if (z)
++ zonefs_init_file_inode(inode, z);
++ else
++ zonefs_init_dir_inode(dir, inode, ztype);
+
+ d_add(dentry, inode);
+ dir->i_size++;
+@@ -1540,100 +665,51 @@ dput:
+ struct zonefs_zone_data {
+ struct super_block *sb;
+ unsigned int nr_zones[ZONEFS_ZTYPE_MAX];
++ sector_t cnv_zone_start;
+ struct blk_zone *zones;
+ };
+
+ /*
+- * Create a zone group and populate it with zone files.
++ * Create the inodes for a zone group.
+ */
+-static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
+- enum zonefs_ztype type)
++static int zonefs_create_zgroup_inodes(struct super_block *sb,
++ enum zonefs_ztype ztype)
+ {
+- struct super_block *sb = zd->sb;
+ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
+- struct blk_zone *zone, *next, *end;
+- const char *zgroup_name;
+- char *file_name;
++ struct zonefs_zone_group *zgroup = &sbi->s_zgroup[ztype];
+ struct dentry *dir, *dent;
+- unsigned int n = 0;
+- int ret;
++ char *file_name;
++ int i, ret = 0;
++
++ if (!zgroup)
++ return -ENOMEM;
+
+ /* If the group is empty, there is nothing to do */
+- if (!zd->nr_zones[type])
++ if (!zgroup->g_nr_zones)
+ return 0;
+
+ file_name = kmalloc(ZONEFS_NAME_MAX, GFP_KERNEL);
+ if (!file_name)
+ return -ENOMEM;
+
+- if (type == ZONEFS_ZTYPE_CNV)
+- zgroup_name = "cnv";
+- else
+- zgroup_name = "seq";
+-
+- dir = zonefs_create_inode(sb->s_root, zgroup_name, NULL, type);
++ dir = zonefs_create_inode(sb->s_root, zonefs_zgroup_name(ztype),
++ NULL, ztype);
+ if (IS_ERR(dir)) {
+ ret = PTR_ERR(dir);
+ goto free;
+ }
+
+- /*
+- * The first zone contains the super block: skip it.
+- */
+- end = zd->zones + bdev_nr_zones(sb->s_bdev);
+- for (zone = &zd->zones[1]; zone < end; zone = next) {
+-
+- next = zone + 1;
+- if (zonefs_zone_type(zone) != type)
+- continue;
+-
+- /*
+- * For conventional zones, contiguous zones can be aggregated
+- * together to form larger files. Note that this overwrites the
+- * length of the first zone of the set of contiguous zones
+- * aggregated together. If one offline or read-only zone is
+- * found, assume that all zones aggregated have the same
+- * condition.
+- */
+- if (type == ZONEFS_ZTYPE_CNV &&
+- (sbi->s_features & ZONEFS_F_AGGRCNV)) {
+- for (; next < end; next++) {
+- if (zonefs_zone_type(next) != type)
+- break;
+- zone->len += next->len;
+- zone->capacity += next->capacity;
+- if (next->cond == BLK_ZONE_COND_READONLY &&
+- zone->cond != BLK_ZONE_COND_OFFLINE)
+- zone->cond = BLK_ZONE_COND_READONLY;
+- else if (next->cond == BLK_ZONE_COND_OFFLINE)
+- zone->cond = BLK_ZONE_COND_OFFLINE;
+- }
+- if (zone->capacity != zone->len) {
+- zonefs_err(sb, "Invalid conventional zone capacity\n");
+- ret = -EINVAL;
+- goto free;
+- }
+- }
+-
+- /*
+- * Use the file number within its group as file name.
+- */
+- snprintf(file_name, ZONEFS_NAME_MAX - 1, "%u", n);
+- dent = zonefs_create_inode(dir, file_name, zone, type);
++ for (i = 0; i < zgroup->g_nr_zones; i++) {
++ /* Use the zone number within its group as the file name */
++ snprintf(file_name, ZONEFS_NAME_MAX - 1, "%u", i);
++ dent = zonefs_create_inode(dir, file_name,
++ &zgroup->g_zones[i], ztype);
+ if (IS_ERR(dent)) {
+ ret = PTR_ERR(dent);
+- goto free;
++ break;
+ }
+-
+- n++;
+ }
+
+- zonefs_info(sb, "Zone group \"%s\" has %u file%s\n",
+- zgroup_name, n, n > 1 ? "s" : "");
+-
+- sbi->s_nr_files[type] = n;
+- ret = 0;
+-
+ free:
+ kfree(file_name);
+
+@@ -1644,21 +720,38 @@ static int zonefs_get_zone_info_cb(struct blk_zone *zone, unsigned int idx,
+ void *data)
+ {
+ struct zonefs_zone_data *zd = data;
++ struct super_block *sb = zd->sb;
++ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
++
++ /*
++ * We do not care about the first zone: it contains the super block
++ * and not exposed as a file.
++ */
++ if (!idx)
++ return 0;
+
+ /*
+- * Count the number of usable zones: the first zone at index 0 contains
+- * the super block and is ignored.
++ * Count the number of zones that will be exposed as files.
++ * For sequential zones, we always have as many files as zones.
++ * FOr conventional zones, the number of files depends on if we have
++ * conventional zones aggregation enabled.
+ */
+ switch (zone->type) {
+ case BLK_ZONE_TYPE_CONVENTIONAL:
+- zone->wp = zone->start + zone->len;
+- if (idx)
+- zd->nr_zones[ZONEFS_ZTYPE_CNV]++;
++ if (sbi->s_features & ZONEFS_F_AGGRCNV) {
++ /* One file per set of contiguous conventional zones */
++ if (!(sbi->s_zgroup[ZONEFS_ZTYPE_CNV].g_nr_zones) ||
++ zone->start != zd->cnv_zone_start)
++ sbi->s_zgroup[ZONEFS_ZTYPE_CNV].g_nr_zones++;
++ zd->cnv_zone_start = zone->start + zone->len;
++ } else {
++ /* One file per zone */
++ sbi->s_zgroup[ZONEFS_ZTYPE_CNV].g_nr_zones++;
++ }
+ break;
+ case BLK_ZONE_TYPE_SEQWRITE_REQ:
+ case BLK_ZONE_TYPE_SEQWRITE_PREF:
+- if (idx)
+- zd->nr_zones[ZONEFS_ZTYPE_SEQ]++;
++ sbi->s_zgroup[ZONEFS_ZTYPE_SEQ].g_nr_zones++;
+ break;
+ default:
+ zonefs_err(zd->sb, "Unsupported zone type 0x%x\n",
+@@ -1698,11 +791,173 @@ static int zonefs_get_zone_info(struct zonefs_zone_data *zd)
+ return 0;
+ }
+
+-static inline void zonefs_cleanup_zone_info(struct zonefs_zone_data *zd)
++static inline void zonefs_free_zone_info(struct zonefs_zone_data *zd)
+ {
+ kvfree(zd->zones);
+ }
+
++/*
++ * Create a zone group and populate it with zone files.
++ */
++static int zonefs_init_zgroup(struct super_block *sb,
++ struct zonefs_zone_data *zd,
++ enum zonefs_ztype ztype)
++{
++ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
++ struct zonefs_zone_group *zgroup = &sbi->s_zgroup[ztype];
++ struct blk_zone *zone, *next, *end;
++ struct zonefs_zone *z;
++ unsigned int n = 0;
++ int ret;
++
++ /* Allocate the zone group. If it is empty, we have nothing to do. */
++ if (!zgroup->g_nr_zones)
++ return 0;
++
++ zgroup->g_zones = kvcalloc(zgroup->g_nr_zones,
++ sizeof(struct zonefs_zone), GFP_KERNEL);
++ if (!zgroup->g_zones)
++ return -ENOMEM;
++
++ /*
++ * Initialize the zone groups using the device zone information.
++ * We always skip the first zone as it contains the super block
++ * and is not use to back a file.
++ */
++ end = zd->zones + bdev_nr_zones(sb->s_bdev);
++ for (zone = &zd->zones[1]; zone < end; zone = next) {
++
++ next = zone + 1;
++ if (zonefs_zone_type(zone) != ztype)
++ continue;
++
++ if (WARN_ON_ONCE(n >= zgroup->g_nr_zones))
++ return -EINVAL;
++
++ /*
++ * For conventional zones, contiguous zones can be aggregated
++ * together to form larger files. Note that this overwrites the
++ * length of the first zone of the set of contiguous zones
++ * aggregated together. If one offline or read-only zone is
++ * found, assume that all zones aggregated have the same
++ * condition.
++ */
++ if (ztype == ZONEFS_ZTYPE_CNV &&
++ (sbi->s_features & ZONEFS_F_AGGRCNV)) {
++ for (; next < end; next++) {
++ if (zonefs_zone_type(next) != ztype)
++ break;
++ zone->len += next->len;
++ zone->capacity += next->capacity;
++ if (next->cond == BLK_ZONE_COND_READONLY &&
++ zone->cond != BLK_ZONE_COND_OFFLINE)
++ zone->cond = BLK_ZONE_COND_READONLY;
++ else if (next->cond == BLK_ZONE_COND_OFFLINE)
++ zone->cond = BLK_ZONE_COND_OFFLINE;
++ }
++ }
++
++ z = &zgroup->g_zones[n];
++ if (ztype == ZONEFS_ZTYPE_CNV)
++ z->z_flags |= ZONEFS_ZONE_CNV;
++ z->z_sector = zone->start;
++ z->z_size = zone->len << SECTOR_SHIFT;
++ if (z->z_size > bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT &&
++ !(sbi->s_features & ZONEFS_F_AGGRCNV)) {
++ zonefs_err(sb,
++ "Invalid zone size %llu (device zone sectors %llu)\n",
++ z->z_size,
++ bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT);
++ return -EINVAL;
++ }
++
++ z->z_capacity = min_t(loff_t, MAX_LFS_FILESIZE,
++ zone->capacity << SECTOR_SHIFT);
++ z->z_wpoffset = zonefs_check_zone_condition(sb, z, zone);
++
++ sb->s_maxbytes = max(z->z_capacity, sb->s_maxbytes);
++ sbi->s_blocks += z->z_capacity >> sb->s_blocksize_bits;
++ sbi->s_used_blocks += z->z_wpoffset >> sb->s_blocksize_bits;
++
++ /*
++ * For sequential zones, make sure that any open zone is closed
++ * first to ensure that the initial number of open zones is 0,
++ * in sync with the open zone accounting done when the mount
++ * option ZONEFS_MNTOPT_EXPLICIT_OPEN is used.
++ */
++ if (ztype == ZONEFS_ZTYPE_SEQ &&
++ (zone->cond == BLK_ZONE_COND_IMP_OPEN ||
++ zone->cond == BLK_ZONE_COND_EXP_OPEN)) {
++ ret = zonefs_zone_mgmt(sb, z, REQ_OP_ZONE_CLOSE);
++ if (ret)
++ return ret;
++ }
++
++ zonefs_account_active(sb, z);
++
++ n++;
++ }
++
++ if (WARN_ON_ONCE(n != zgroup->g_nr_zones))
++ return -EINVAL;
++
++ zonefs_info(sb, "Zone group \"%s\" has %u file%s\n",
++ zonefs_zgroup_name(ztype),
++ zgroup->g_nr_zones,
++ zgroup->g_nr_zones > 1 ? "s" : "");
++
++ return 0;
++}
++
++static void zonefs_free_zgroups(struct super_block *sb)
++{
++ struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
++ enum zonefs_ztype ztype;
++
++ if (!sbi)
++ return;
++
++ for (ztype = 0; ztype < ZONEFS_ZTYPE_MAX; ztype++) {
++ kvfree(sbi->s_zgroup[ztype].g_zones);
++ sbi->s_zgroup[ztype].g_zones = NULL;
++ }
++}
++
++/*
++ * Create a zone group and populate it with zone files.
++ */
++static int zonefs_init_zgroups(struct super_block *sb)
++{
++ struct zonefs_zone_data zd;
++ enum zonefs_ztype ztype;
++ int ret;
++
++ /* First get the device zone information */
++ memset(&zd, 0, sizeof(struct zonefs_zone_data));
++ zd.sb = sb;
++ ret = zonefs_get_zone_info(&zd);
++ if (ret)
++ goto cleanup;
++
++ /* Allocate and initialize the zone groups */
++ for (ztype = 0; ztype < ZONEFS_ZTYPE_MAX; ztype++) {
++ ret = zonefs_init_zgroup(sb, &zd, ztype);
++ if (ret) {
++ zonefs_info(sb,
++ "Zone group \"%s\" initialization failed\n",
++ zonefs_zgroup_name(ztype));
++ break;
++ }
++ }
++
++cleanup:
++ zonefs_free_zone_info(&zd);
++ if (ret)
++ zonefs_free_zgroups(sb);
++
++ return ret;
++}
++
+ /*
+ * Read super block information from the device.
+ */
+@@ -1785,6 +1040,14 @@ free_page:
+ return ret;
+ }
+
++static const struct super_operations zonefs_sops = {
++ .alloc_inode = zonefs_alloc_inode,
++ .free_inode = zonefs_free_inode,
++ .statfs = zonefs_statfs,
++ .remount_fs = zonefs_remount,
++ .show_options = zonefs_show_options,
++};
++
+ /*
+ * Check that the device is zoned. If it is, get the list of zones and create
+ * sub-directories and files according to the device zone configuration and
+@@ -1792,7 +1055,6 @@ free_page:
+ */
+ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
+ {
+- struct zonefs_zone_data zd;
+ struct zonefs_sb_info *sbi;
+ struct inode *inode;
+ enum zonefs_ztype t;
+@@ -1845,16 +1107,6 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
+ if (ret)
+ return ret;
+
+- memset(&zd, 0, sizeof(struct zonefs_zone_data));
+- zd.sb = sb;
+- ret = zonefs_get_zone_info(&zd);
+- if (ret)
+- goto cleanup;
+-
+- ret = zonefs_sysfs_register(sb);
+- if (ret)
+- goto cleanup;
+-
+ zonefs_info(sb, "Mounting %u zones", bdev_nr_zones(sb->s_bdev));
+
+ if (!sbi->s_max_wro_seq_files &&
+@@ -1865,6 +1117,11 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
+ sbi->s_mount_opts &= ~ZONEFS_MNTOPT_EXPLICIT_OPEN;
+ }
+
++ /* Initialize the zone groups */
++ ret = zonefs_init_zgroups(sb);
++ if (ret)
++ goto cleanup;
++
+ /* Create root directory inode */
+ ret = -ENOMEM;
+ inode = new_inode(sb);
+@@ -1884,13 +1141,19 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
+
+ /* Create and populate files in zone groups directories */
+ for (t = 0; t < ZONEFS_ZTYPE_MAX; t++) {
+- ret = zonefs_create_zgroup(&zd, t);
++ ret = zonefs_create_zgroup_inodes(sb, t);
+ if (ret)
+- break;
++ goto cleanup;
+ }
+
++ ret = zonefs_sysfs_register(sb);
++ if (ret)
++ goto cleanup;
++
++ return 0;
++
+ cleanup:
+- zonefs_cleanup_zone_info(&zd);
++ zonefs_free_zgroups(sb);
+
+ return ret;
+ }
+@@ -1909,6 +1172,7 @@ static void zonefs_kill_super(struct super_block *sb)
+ d_genocide(sb->s_root);
+
+ zonefs_sysfs_unregister(sb);
++ zonefs_free_zgroups(sb);
+ kill_block_super(sb);
+ kfree(sbi);
+ }
+diff --git a/fs/zonefs/trace.h b/fs/zonefs/trace.h
+index 42edcfd393ed2..9969db3a9c7dc 100644
+--- a/fs/zonefs/trace.h
++++ b/fs/zonefs/trace.h
+@@ -20,8 +20,9 @@
+ #define show_dev(dev) MAJOR(dev), MINOR(dev)
+
+ TRACE_EVENT(zonefs_zone_mgmt,
+- TP_PROTO(struct inode *inode, enum req_op op),
+- TP_ARGS(inode, op),
++ TP_PROTO(struct super_block *sb, struct zonefs_zone *z,
++ enum req_op op),
++ TP_ARGS(sb, z, op),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(ino_t, ino)
+@@ -30,12 +31,12 @@ TRACE_EVENT(zonefs_zone_mgmt,
+ __field(sector_t, nr_sectors)
+ ),
+ TP_fast_assign(
+- __entry->dev = inode->i_sb->s_dev;
+- __entry->ino = inode->i_ino;
++ __entry->dev = sb->s_dev;
++ __entry->ino =
++ z->z_sector >> ZONEFS_SB(sb)->s_zone_sectors_shift;
+ __entry->op = op;
+- __entry->sector = ZONEFS_I(inode)->i_zsector;
+- __entry->nr_sectors =
+- ZONEFS_I(inode)->i_zone_size >> SECTOR_SHIFT;
++ __entry->sector = z->z_sector;
++ __entry->nr_sectors = z->z_size >> SECTOR_SHIFT;
+ ),
+ TP_printk("bdev=(%d,%d), ino=%lu op=%s, sector=%llu, nr_sectors=%llu",
+ show_dev(__entry->dev), (unsigned long)__entry->ino,
+@@ -58,9 +59,10 @@ TRACE_EVENT(zonefs_file_dio_append,
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ino = inode->i_ino;
+- __entry->sector = ZONEFS_I(inode)->i_zsector;
++ __entry->sector = zonefs_inode_zone(inode)->z_sector;
+ __entry->size = size;
+- __entry->wpoffset = ZONEFS_I(inode)->i_wpoffset;
++ __entry->wpoffset =
++ zonefs_inode_zone(inode)->z_wpoffset;
+ __entry->ret = ret;
+ ),
+ TP_printk("bdev=(%d, %d), ino=%lu, sector=%llu, size=%zu, wpoffset=%llu, ret=%zu",
+diff --git a/fs/zonefs/zonefs.h b/fs/zonefs/zonefs.h
+index 1dbe78119ff16..2d626e18b1411 100644
+--- a/fs/zonefs/zonefs.h
++++ b/fs/zonefs/zonefs.h
+@@ -39,31 +39,47 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
+ return ZONEFS_ZTYPE_SEQ;
+ }
+
+-#define ZONEFS_ZONE_OPEN (1U << 0)
+-#define ZONEFS_ZONE_ACTIVE (1U << 1)
+-#define ZONEFS_ZONE_OFFLINE (1U << 2)
+-#define ZONEFS_ZONE_READONLY (1U << 3)
++#define ZONEFS_ZONE_INIT_MODE (1U << 0)
++#define ZONEFS_ZONE_OPEN (1U << 1)
++#define ZONEFS_ZONE_ACTIVE (1U << 2)
++#define ZONEFS_ZONE_OFFLINE (1U << 3)
++#define ZONEFS_ZONE_READONLY (1U << 4)
++#define ZONEFS_ZONE_CNV (1U << 31)
+
+ /*
+- * In-memory inode data.
++ * In-memory per-file inode zone data.
+ */
+-struct zonefs_inode_info {
+- struct inode i_vnode;
++struct zonefs_zone {
++ /* Zone state flags */
++ unsigned int z_flags;
+
+- /* File zone type */
+- enum zonefs_ztype i_ztype;
++ /* Zone start sector (512B unit) */
++ sector_t z_sector;
+
+- /* File zone start sector (512B unit) */
+- sector_t i_zsector;
++ /* Zone size (bytes) */
++ loff_t z_size;
+
+- /* File zone write pointer position (sequential zones only) */
+- loff_t i_wpoffset;
++ /* Zone capacity (file maximum size, bytes) */
++ loff_t z_capacity;
+
+- /* File maximum size */
+- loff_t i_max_size;
++ /* Write pointer offset in the zone (sequential zones only, bytes) */
++ loff_t z_wpoffset;
++};
+
+- /* File zone size */
+- loff_t i_zone_size;
++/*
++ * In memory zone group information: all zones of a group are exposed
++ * as files, one file per zone.
++ */
++struct zonefs_zone_group {
++ unsigned int g_nr_zones;
++ struct zonefs_zone *g_zones;
++};
++
++/*
++ * In-memory inode data.
++ */
++struct zonefs_inode_info {
++ struct inode i_vnode;
+
+ /*
+ * To serialise fully against both syscall and mmap based IO and
+@@ -82,7 +98,6 @@ struct zonefs_inode_info {
+
+ /* guarded by i_truncate_mutex */
+ unsigned int i_wr_refcnt;
+- unsigned int i_flags;
+ };
+
+ static inline struct zonefs_inode_info *ZONEFS_I(struct inode *inode)
+@@ -90,6 +105,31 @@ static inline struct zonefs_inode_info *ZONEFS_I(struct inode *inode)
+ return container_of(inode, struct zonefs_inode_info, i_vnode);
+ }
+
++static inline bool zonefs_zone_is_cnv(struct zonefs_zone *z)
++{
++ return z->z_flags & ZONEFS_ZONE_CNV;
++}
++
++static inline bool zonefs_zone_is_seq(struct zonefs_zone *z)
++{
++ return !zonefs_zone_is_cnv(z);
++}
++
++static inline struct zonefs_zone *zonefs_inode_zone(struct inode *inode)
++{
++ return inode->i_private;
++}
++
++static inline bool zonefs_inode_is_cnv(struct inode *inode)
++{
++ return zonefs_zone_is_cnv(zonefs_inode_zone(inode));
++}
++
++static inline bool zonefs_inode_is_seq(struct inode *inode)
++{
++ return zonefs_zone_is_seq(zonefs_inode_zone(inode));
++}
++
+ /*
+ * On-disk super block (block 0).
+ */
+@@ -181,7 +221,7 @@ struct zonefs_sb_info {
+ uuid_t s_uuid;
+ unsigned int s_zone_sectors_shift;
+
+- unsigned int s_nr_files[ZONEFS_ZTYPE_MAX];
++ struct zonefs_zone_group s_zgroup[ZONEFS_ZTYPE_MAX];
+
+ loff_t s_blocks;
+ loff_t s_used_blocks;
+@@ -209,6 +249,28 @@ static inline struct zonefs_sb_info *ZONEFS_SB(struct super_block *sb)
+ #define zonefs_warn(sb, format, args...) \
+ pr_warn("zonefs (%s) WARNING: " format, sb->s_id, ## args)
+
++/* In super.c */
++void zonefs_inode_account_active(struct inode *inode);
++int zonefs_inode_zone_mgmt(struct inode *inode, enum req_op op);
++void zonefs_i_size_write(struct inode *inode, loff_t isize);
++void zonefs_update_stats(struct inode *inode, loff_t new_isize);
++void __zonefs_io_error(struct inode *inode, bool write);
++
++static inline void zonefs_io_error(struct inode *inode, bool write)
++{
++ struct zonefs_inode_info *zi = ZONEFS_I(inode);
++
++ mutex_lock(&zi->i_truncate_mutex);
++ __zonefs_io_error(inode, write);
++ mutex_unlock(&zi->i_truncate_mutex);
++}
++
++/* In file.c */
++extern const struct address_space_operations zonefs_file_aops;
++extern const struct file_operations zonefs_file_operations;
++int zonefs_file_truncate(struct inode *inode, loff_t isize);
++
++/* In sysfs.c */
+ int zonefs_sysfs_register(struct super_block *sb);
+ void zonefs_sysfs_unregister(struct super_block *sb);
+ int zonefs_sysfs_init(void);
+diff --git a/include/linux/io_uring.h b/include/linux/io_uring.h
+index 0ded9e271523f..a1484cdb3158e 100644
+--- a/include/linux/io_uring.h
++++ b/include/linux/io_uring.h
+@@ -26,7 +26,7 @@ struct io_uring_cmd {
+ const void *cmd;
+ union {
+ /* callback to defer completions to task context */
+- void (*task_work_cb)(struct io_uring_cmd *cmd);
++ void (*task_work_cb)(struct io_uring_cmd *cmd, unsigned);
+ /* used for polled completion */
+ void *cookie;
+ };
+@@ -38,9 +38,10 @@ struct io_uring_cmd {
+ #if defined(CONFIG_IO_URING)
+ int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
+ struct iov_iter *iter, void *ioucmd);
+-void io_uring_cmd_done(struct io_uring_cmd *cmd, ssize_t ret, ssize_t res2);
++void io_uring_cmd_done(struct io_uring_cmd *cmd, ssize_t ret, ssize_t res2,
++ unsigned issue_flags);
+ void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
+- void (*task_work_cb)(struct io_uring_cmd *));
++ void (*task_work_cb)(struct io_uring_cmd *, unsigned));
+ struct sock *io_uring_get_socket(struct file *file);
+ void __io_uring_cancel(bool cancel_all);
+ void __io_uring_free(struct task_struct *tsk);
+@@ -71,11 +72,11 @@ static inline int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
+ return -EOPNOTSUPP;
+ }
+ static inline void io_uring_cmd_done(struct io_uring_cmd *cmd, ssize_t ret,
+- ssize_t ret2)
++ ssize_t ret2, unsigned issue_flags)
+ {
+ }
+ static inline void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
+- void (*task_work_cb)(struct io_uring_cmd *))
++ void (*task_work_cb)(struct io_uring_cmd *, unsigned))
+ {
+ }
+ static inline struct sock *io_uring_get_socket(struct file *file)
+diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
+index 90b2fb0292cb1..012fa0d171b27 100644
+--- a/include/trace/events/rcu.h
++++ b/include/trace/events/rcu.h
+@@ -768,7 +768,7 @@ TRACE_EVENT_RCU(rcu_torture_read,
+ TP_ARGS(rcutorturename, rhp, secs, c_old, c),
+
+ TP_STRUCT__entry(
+- __field(char, rcutorturename[RCUTORTURENAME_LEN])
++ __array(char, rcutorturename, RCUTORTURENAME_LEN)
+ __field(struct rcu_head *, rhp)
+ __field(unsigned long, secs)
+ __field(unsigned long, c_old)
+diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
+index 655d92e803e14..79a443c65ea93 100644
+--- a/include/xen/interface/platform.h
++++ b/include/xen/interface/platform.h
+@@ -483,6 +483,8 @@ struct xenpf_symdata {
+ };
+ DEFINE_GUEST_HANDLE_STRUCT(xenpf_symdata);
+
++#define XENPF_get_dom0_console 64
++
+ struct xen_platform_op {
+ uint32_t cmd;
+ uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
+@@ -506,6 +508,7 @@ struct xen_platform_op {
+ struct xenpf_mem_hotadd mem_add;
+ struct xenpf_core_parking core_parking;
+ struct xenpf_symdata symdata;
++ struct dom0_vga_console_info dom0_console;
+ uint8_t pad[128];
+ } u;
+ };
+diff --git a/io_uring/alloc_cache.h b/io_uring/alloc_cache.h
+index 729793ae97127..c2cde88aeed53 100644
+--- a/io_uring/alloc_cache.h
++++ b/io_uring/alloc_cache.h
+@@ -27,6 +27,7 @@ static inline struct io_cache_entry *io_alloc_cache_get(struct io_alloc_cache *c
+ struct hlist_node *node = cache->list.first;
+
+ hlist_del(node);
++ cache->nr_cached--;
+ return container_of(node, struct io_cache_entry, node);
+ }
+
+diff --git a/io_uring/poll.c b/io_uring/poll.c
+index 56dbd1863c785..4788073ec45d2 100644
+--- a/io_uring/poll.c
++++ b/io_uring/poll.c
+@@ -742,6 +742,7 @@ int io_arm_poll_handler(struct io_kiocb *req, unsigned issue_flags)
+ apoll = io_req_alloc_apoll(req, issue_flags);
+ if (!apoll)
+ return IO_APOLL_ABORTED;
++ req->flags &= ~(REQ_F_SINGLE_POLL | REQ_F_DOUBLE_POLL);
+ req->flags |= REQ_F_POLLED;
+ ipt.pt._qproc = io_async_queue_proc;
+
+diff --git a/io_uring/rsrc.h b/io_uring/rsrc.h
+index 81445a477622b..d60c758326b42 100644
+--- a/io_uring/rsrc.h
++++ b/io_uring/rsrc.h
+@@ -143,15 +143,13 @@ static inline void io_req_set_rsrc_node(struct io_kiocb *req,
+ unsigned int issue_flags)
+ {
+ if (!req->rsrc_node) {
+- req->rsrc_node = ctx->rsrc_node;
++ io_ring_submit_lock(ctx, issue_flags);
+
+- if (!(issue_flags & IO_URING_F_UNLOCKED)) {
+- lockdep_assert_held(&ctx->uring_lock);
++ lockdep_assert_held(&ctx->uring_lock);
+
+- io_charge_rsrc_node(ctx);
+- } else {
+- percpu_ref_get(&req->rsrc_node->refs);
+- }
++ req->rsrc_node = ctx->rsrc_node;
++ io_charge_rsrc_node(ctx);
++ io_ring_submit_unlock(ctx, issue_flags);
+ }
+ }
+
+diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c
+index 18dfc5f6a8b72..92f310dfb9fd6 100644
+--- a/io_uring/uring_cmd.c
++++ b/io_uring/uring_cmd.c
+@@ -15,12 +15,13 @@
+ static void io_uring_cmd_work(struct io_kiocb *req, bool *locked)
+ {
+ struct io_uring_cmd *ioucmd = io_kiocb_to_cmd(req, struct io_uring_cmd);
++ unsigned issue_flags = *locked ? 0 : IO_URING_F_UNLOCKED;
+
+- ioucmd->task_work_cb(ioucmd);
++ ioucmd->task_work_cb(ioucmd, issue_flags);
+ }
+
+ void io_uring_cmd_complete_in_task(struct io_uring_cmd *ioucmd,
+- void (*task_work_cb)(struct io_uring_cmd *))
++ void (*task_work_cb)(struct io_uring_cmd *, unsigned))
+ {
+ struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
+
+@@ -42,7 +43,8 @@ static inline void io_req_set_cqe32_extra(struct io_kiocb *req,
+ * Called by consumers of io_uring_cmd, if they originally returned
+ * -EIOCBQUEUED upon receiving the command.
+ */
+-void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2)
++void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2,
++ unsigned issue_flags)
+ {
+ struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
+
+@@ -56,7 +58,7 @@ void io_uring_cmd_done(struct io_uring_cmd *ioucmd, ssize_t ret, ssize_t res2)
+ /* order with io_iopoll_req_issued() checking ->iopoll_complete */
+ smp_store_release(&req->iopoll_completed, 1);
+ else
+- __io_req_complete(req, 0);
++ __io_req_complete(req, issue_flags);
+ }
+ EXPORT_SYMBOL_GPL(io_uring_cmd_done);
+
+diff --git a/kernel/compat.c b/kernel/compat.c
+index 55551989d9da5..fb50f29d9b361 100644
+--- a/kernel/compat.c
++++ b/kernel/compat.c
+@@ -152,7 +152,7 @@ COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t, pid, unsigned int, len,
+ if (len & (sizeof(compat_ulong_t)-1))
+ return -EINVAL;
+
+- if (!alloc_cpumask_var(&mask, GFP_KERNEL))
++ if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
+ return -ENOMEM;
+
+ ret = sched_getaffinity(pid, mask);
+diff --git a/kernel/kcsan/Makefile b/kernel/kcsan/Makefile
+index 4f35d1bced6a2..a45f3dfc8d141 100644
+--- a/kernel/kcsan/Makefile
++++ b/kernel/kcsan/Makefile
+@@ -16,5 +16,6 @@ obj-y := core.o debugfs.o report.o
+ KCSAN_INSTRUMENT_BARRIERS_selftest.o := y
+ obj-$(CONFIG_KCSAN_SELFTEST) += selftest.o
+
+-CFLAGS_kcsan_test.o := $(CFLAGS_KCSAN) -g -fno-omit-frame-pointer
++CFLAGS_kcsan_test.o := $(CFLAGS_KCSAN) -fno-omit-frame-pointer
++CFLAGS_kcsan_test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
+ obj-$(CONFIG_KCSAN_KUNIT_TEST) += kcsan_test.o
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index 9ebfd484189b3..b23dcbeacdf33 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -8304,14 +8304,14 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
+ if (len & (sizeof(unsigned long)-1))
+ return -EINVAL;
+
+- if (!alloc_cpumask_var(&mask, GFP_KERNEL))
++ if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
+ return -ENOMEM;
+
+ ret = sched_getaffinity(pid, mask);
+ if (ret == 0) {
+ unsigned int retlen = min(len, cpumask_size());
+
+- if (copy_to_user(user_mask_ptr, mask, retlen))
++ if (copy_to_user(user_mask_ptr, cpumask_bits(mask), retlen))
+ ret = -EFAULT;
+ else
+ ret = retlen;
+diff --git a/kernel/trace/kprobe_event_gen_test.c b/kernel/trace/kprobe_event_gen_test.c
+index c736487fc0e48..e0c420eb0b2b4 100644
+--- a/kernel/trace/kprobe_event_gen_test.c
++++ b/kernel/trace/kprobe_event_gen_test.c
+@@ -146,7 +146,7 @@ static int __init test_gen_kprobe_cmd(void)
+ if (trace_event_file_is_valid(gen_kprobe_test))
+ gen_kprobe_test = NULL;
+ /* We got an error after creating the event, delete it */
+- ret = kprobe_event_delete("gen_kprobe_test");
++ kprobe_event_delete("gen_kprobe_test");
+ goto out;
+ }
+
+@@ -211,7 +211,7 @@ static int __init test_gen_kretprobe_cmd(void)
+ if (trace_event_file_is_valid(gen_kretprobe_test))
+ gen_kretprobe_test = NULL;
+ /* We got an error after creating the event, delete it */
+- ret = kprobe_event_delete("gen_kretprobe_test");
++ kprobe_event_delete("gen_kretprobe_test");
+ goto out;
+ }
+
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index 888980257340f..78d69b9488e45 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -5727,7 +5727,9 @@ static const char readme_msg[] =
+ "\t .syscall display a syscall id as a syscall name\n"
+ "\t .log2 display log2 value rather than raw number\n"
+ "\t .buckets=size display values in groups of size rather than raw number\n"
+- "\t .usecs display a common_timestamp in microseconds\n\n"
++ "\t .usecs display a common_timestamp in microseconds\n"
++ "\t .percent display a number of percentage value\n"
++ "\t .graph display a bar-graph of a value\n\n"
+ "\t The 'pause' parameter can be used to pause an existing hist\n"
+ "\t trigger or to start a hist trigger but not log any events\n"
+ "\t until told to do so. 'continue' can be used to start or\n"
+diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
+index e3df03cdecbcb..2b2120ed2460f 100644
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -506,6 +506,8 @@ enum hist_field_flags {
+ HIST_FIELD_FL_ALIAS = 1 << 16,
+ HIST_FIELD_FL_BUCKET = 1 << 17,
+ HIST_FIELD_FL_CONST = 1 << 18,
++ HIST_FIELD_FL_PERCENT = 1 << 19,
++ HIST_FIELD_FL_GRAPH = 1 << 20,
+ };
+
+ struct var_defs {
+@@ -1708,6 +1710,10 @@ static const char *get_hist_field_flags(struct hist_field *hist_field)
+ flags_str = "buckets";
+ else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP_USECS)
+ flags_str = "usecs";
++ else if (hist_field->flags & HIST_FIELD_FL_PERCENT)
++ flags_str = "percent";
++ else if (hist_field->flags & HIST_FIELD_FL_GRAPH)
++ flags_str = "graph";
+
+ return flags_str;
+ }
+@@ -2320,6 +2326,14 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
+ if (ret || !(*buckets))
+ goto error;
+ *flags |= HIST_FIELD_FL_BUCKET;
++ } else if (strncmp(modifier, "percent", 7) == 0) {
++ if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
++ goto error;
++ *flags |= HIST_FIELD_FL_PERCENT;
++ } else if (strncmp(modifier, "graph", 5) == 0) {
++ if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
++ goto error;
++ *flags |= HIST_FIELD_FL_GRAPH;
+ } else {
+ error:
+ hist_err(tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(modifier));
+@@ -4179,6 +4193,15 @@ static int __create_val_field(struct hist_trigger_data *hist_data,
+ goto out;
+ }
+
++ /* Some types cannot be a value */
++ if (hist_field->flags & (HIST_FIELD_FL_GRAPH | HIST_FIELD_FL_PERCENT |
++ HIST_FIELD_FL_BUCKET | HIST_FIELD_FL_LOG2 |
++ HIST_FIELD_FL_SYM | HIST_FIELD_FL_SYM_OFFSET |
++ HIST_FIELD_FL_SYSCALL | HIST_FIELD_FL_STACKTRACE)) {
++ hist_err(file->tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(field_str));
++ ret = -EINVAL;
++ }
++
+ hist_data->fields[val_idx] = hist_field;
+
+ ++hist_data->n_vals;
+@@ -5297,33 +5320,101 @@ static void hist_trigger_print_key(struct seq_file *m,
+ seq_puts(m, "}");
+ }
+
++/* Get the 100 times of the percentage of @val in @total */
++static inline unsigned int __get_percentage(u64 val, u64 total)
++{
++ if (!total)
++ goto div0;
++
++ if (val < (U64_MAX / 10000))
++ return (unsigned int)div64_ul(val * 10000, total);
++
++ total = div64_u64(total, 10000);
++ if (!total)
++ goto div0;
++
++ return (unsigned int)div64_ul(val, total);
++div0:
++ return val ? UINT_MAX : 0;
++}
++
++#define BAR_CHAR '#'
++
++static inline const char *__fill_bar_str(char *buf, int size, u64 val, u64 max)
++{
++ unsigned int len = __get_percentage(val, max);
++ int i;
++
++ if (len == UINT_MAX) {
++ snprintf(buf, size, "[ERROR]");
++ return buf;
++ }
++
++ len = len * size / 10000;
++ for (i = 0; i < len && i < size; i++)
++ buf[i] = BAR_CHAR;
++ while (i < size)
++ buf[i++] = ' ';
++ buf[size] = '\0';
++
++ return buf;
++}
++
++struct hist_val_stat {
++ u64 max;
++ u64 total;
++};
++
++static void hist_trigger_print_val(struct seq_file *m, unsigned int idx,
++ const char *field_name, unsigned long flags,
++ struct hist_val_stat *stats,
++ struct tracing_map_elt *elt)
++{
++ u64 val = tracing_map_read_sum(elt, idx);
++ unsigned int pc;
++ char bar[21];
++
++ if (flags & HIST_FIELD_FL_PERCENT) {
++ pc = __get_percentage(val, stats[idx].total);
++ if (pc == UINT_MAX)
++ seq_printf(m, " %s (%%):[ERROR]", field_name);
++ else
++ seq_printf(m, " %s (%%): %3u.%02u", field_name,
++ pc / 100, pc % 100);
++ } else if (flags & HIST_FIELD_FL_GRAPH) {
++ seq_printf(m, " %s: %20s", field_name,
++ __fill_bar_str(bar, 20, val, stats[idx].max));
++ } else if (flags & HIST_FIELD_FL_HEX) {
++ seq_printf(m, " %s: %10llx", field_name, val);
++ } else {
++ seq_printf(m, " %s: %10llu", field_name, val);
++ }
++}
++
+ static void hist_trigger_entry_print(struct seq_file *m,
+ struct hist_trigger_data *hist_data,
++ struct hist_val_stat *stats,
+ void *key,
+ struct tracing_map_elt *elt)
+ {
+ const char *field_name;
+- unsigned int i;
++ unsigned int i = HITCOUNT_IDX;
++ unsigned long flags;
+
+ hist_trigger_print_key(m, hist_data, key, elt);
+
+- seq_printf(m, " hitcount: %10llu",
+- tracing_map_read_sum(elt, HITCOUNT_IDX));
++ /* At first, show the raw hitcount always */
++ hist_trigger_print_val(m, i, "hitcount", 0, stats, elt);
+
+ for (i = 1; i < hist_data->n_vals; i++) {
+ field_name = hist_field_name(hist_data->fields[i], 0);
++ flags = hist_data->fields[i]->flags;
+
+- if (hist_data->fields[i]->flags & HIST_FIELD_FL_VAR ||
+- hist_data->fields[i]->flags & HIST_FIELD_FL_EXPR)
++ if (flags & HIST_FIELD_FL_VAR || flags & HIST_FIELD_FL_EXPR)
+ continue;
+
+- if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
+- seq_printf(m, " %s: %10llx", field_name,
+- tracing_map_read_sum(elt, i));
+- } else {
+- seq_printf(m, " %s: %10llu", field_name,
+- tracing_map_read_sum(elt, i));
+- }
++ seq_puts(m, " ");
++ hist_trigger_print_val(m, i, field_name, flags, stats, elt);
+ }
+
+ print_actions(m, hist_data, elt);
+@@ -5336,7 +5427,9 @@ static int print_entries(struct seq_file *m,
+ {
+ struct tracing_map_sort_entry **sort_entries = NULL;
+ struct tracing_map *map = hist_data->map;
+- int i, n_entries;
++ int i, j, n_entries;
++ struct hist_val_stat *stats = NULL;
++ u64 val;
+
+ n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
+ hist_data->n_sort_keys,
+@@ -5344,11 +5437,34 @@ static int print_entries(struct seq_file *m,
+ if (n_entries < 0)
+ return n_entries;
+
++ /* Calculate the max and the total for each field if needed. */
++ for (j = 0; j < hist_data->n_vals; j++) {
++ if (!(hist_data->fields[j]->flags &
++ (HIST_FIELD_FL_PERCENT | HIST_FIELD_FL_GRAPH)))
++ continue;
++ if (!stats) {
++ stats = kcalloc(hist_data->n_vals, sizeof(*stats),
++ GFP_KERNEL);
++ if (!stats) {
++ n_entries = -ENOMEM;
++ goto out;
++ }
++ }
++ for (i = 0; i < n_entries; i++) {
++ val = tracing_map_read_sum(sort_entries[i]->elt, j);
++ stats[j].total += val;
++ if (stats[j].max < val)
++ stats[j].max = val;
++ }
++ }
++
+ for (i = 0; i < n_entries; i++)
+- hist_trigger_entry_print(m, hist_data,
++ hist_trigger_entry_print(m, hist_data, stats,
+ sort_entries[i]->key,
+ sort_entries[i]->elt);
+
++ kfree(stats);
++out:
+ tracing_map_destroy_sort_entries(sort_entries, n_entries);
+
+ return n_entries;
+diff --git a/lib/zstd/common/zstd_deps.h b/lib/zstd/common/zstd_deps.h
+index 7a5bf44839c9c..f06df065dec01 100644
+--- a/lib/zstd/common/zstd_deps.h
++++ b/lib/zstd/common/zstd_deps.h
+@@ -84,7 +84,7 @@ static uint64_t ZSTD_div64(uint64_t dividend, uint32_t divisor) {
+
+ #include <linux/kernel.h>
+
+-#define assert(x) WARN_ON((x))
++#define assert(x) WARN_ON(!(x))
+
+ #endif /* ZSTD_DEPS_ASSERT */
+ #endif /* ZSTD_DEPS_NEED_ASSERT */
+diff --git a/net/can/bcm.c b/net/can/bcm.c
+index 27706f6ace34a..a962ec2b8ba5b 100644
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -941,6 +941,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+
+ cf = op->frames + op->cfsiz * i;
+ err = memcpy_from_msg((u8 *)cf, msg, op->cfsiz);
++ if (err < 0)
++ goto free_op;
+
+ if (op->flags & CAN_FD_FRAME) {
+ if (cf->len > 64)
+@@ -950,12 +952,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ err = -EINVAL;
+ }
+
+- if (err < 0) {
+- if (op->frames != &op->sframe)
+- kfree(op->frames);
+- kfree(op);
+- return err;
+- }
++ if (err < 0)
++ goto free_op;
+
+ if (msg_head->flags & TX_CP_CAN_ID) {
+ /* copy can_id into frame */
+@@ -1026,6 +1024,12 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ bcm_tx_start_timer(op);
+
+ return msg_head->nframes * op->cfsiz + MHSIZ;
++
++free_op:
++ if (op->frames != &op->sframe)
++ kfree(op->frames);
++ kfree(op);
++ return err;
+ }
+
+ /*
+diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
+index 4177e96170703..848b60c9ef79e 100644
+--- a/net/can/j1939/transport.c
++++ b/net/can/j1939/transport.c
+@@ -1124,8 +1124,6 @@ static void __j1939_session_cancel(struct j1939_session *session,
+
+ if (session->sk)
+ j1939_sk_send_loop_abort(session->sk, session->err);
+- else
+- j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
+ }
+
+ static void j1939_session_cancel(struct j1939_session *session,
+@@ -1140,6 +1138,9 @@ static void j1939_session_cancel(struct j1939_session *session,
+ }
+
+ j1939_session_list_unlock(session->priv);
++
++ if (!session->sk)
++ j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
+ }
+
+ static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
+@@ -1253,6 +1254,9 @@ static enum hrtimer_restart j1939_tp_rxtimer(struct hrtimer *hrtimer)
+ __j1939_session_cancel(session, J1939_XTP_ABORT_TIMEOUT);
+ }
+ j1939_session_list_unlock(session->priv);
++
++ if (!session->sk)
++ j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
+ }
+
+ j1939_session_put(session);
+diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
+index 39a6088080e93..a16f0445023aa 100644
+--- a/net/hsr/hsr_framereg.c
++++ b/net/hsr/hsr_framereg.c
+@@ -422,7 +422,7 @@ void hsr_addr_subst_dest(struct hsr_node *node_src, struct sk_buff *skb,
+ node_dst = find_node_by_addr_A(&port->hsr->node_db,
+ eth_hdr(skb)->h_dest);
+ if (!node_dst) {
+- if (net_ratelimit())
++ if (port->hsr->prot_version != PRP_V1 && net_ratelimit())
+ netdev_err(skb->dev, "%s: Unknown node\n", __func__);
+ return;
+ }
+diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
+index b3ab6d9d752ea..05aa32696e7c2 100644
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -2153,6 +2153,7 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
+ switch (skst) {
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
++ case TCP_LAST_ACK:
+ break;
+ case TCP_ESTABLISHED:
+ case TCP_CLOSE_WAIT:
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index e73f9efc54c12..83f35ecacf24f 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -997,7 +997,9 @@ static int copy_to_user_aead(struct xfrm_algo_aead *aead, struct sk_buff *skb)
+ return -EMSGSIZE;
+
+ ap = nla_data(nla);
+- memcpy(ap, aead, sizeof(*aead));
++ strscpy_pad(ap->alg_name, aead->alg_name, sizeof(ap->alg_name));
++ ap->alg_key_len = aead->alg_key_len;
++ ap->alg_icv_len = aead->alg_icv_len;
+
+ if (redact_secret && aead->alg_key_len)
+ memset(ap->alg_key, 0, (aead->alg_key_len + 7) / 8);
+@@ -1017,7 +1019,8 @@ static int copy_to_user_ealg(struct xfrm_algo *ealg, struct sk_buff *skb)
+ return -EMSGSIZE;
+
+ ap = nla_data(nla);
+- memcpy(ap, ealg, sizeof(*ealg));
++ strscpy_pad(ap->alg_name, ealg->alg_name, sizeof(ap->alg_name));
++ ap->alg_key_len = ealg->alg_key_len;
+
+ if (redact_secret && ealg->alg_key_len)
+ memset(ap->alg_key, 0, (ealg->alg_key_len + 7) / 8);
+@@ -1028,6 +1031,40 @@ static int copy_to_user_ealg(struct xfrm_algo *ealg, struct sk_buff *skb)
+ return 0;
+ }
+
++static int copy_to_user_calg(struct xfrm_algo *calg, struct sk_buff *skb)
++{
++ struct nlattr *nla = nla_reserve(skb, XFRMA_ALG_COMP, sizeof(*calg));
++ struct xfrm_algo *ap;
++
++ if (!nla)
++ return -EMSGSIZE;
++
++ ap = nla_data(nla);
++ strscpy_pad(ap->alg_name, calg->alg_name, sizeof(ap->alg_name));
++ ap->alg_key_len = 0;
++
++ return 0;
++}
++
++static int copy_to_user_encap(struct xfrm_encap_tmpl *ep, struct sk_buff *skb)
++{
++ struct nlattr *nla = nla_reserve(skb, XFRMA_ENCAP, sizeof(*ep));
++ struct xfrm_encap_tmpl *uep;
++
++ if (!nla)
++ return -EMSGSIZE;
++
++ uep = nla_data(nla);
++ memset(uep, 0, sizeof(*uep));
++
++ uep->encap_type = ep->encap_type;
++ uep->encap_sport = ep->encap_sport;
++ uep->encap_dport = ep->encap_dport;
++ uep->encap_oa = ep->encap_oa;
++
++ return 0;
++}
++
+ static int xfrm_smark_put(struct sk_buff *skb, struct xfrm_mark *m)
+ {
+ int ret = 0;
+@@ -1083,12 +1120,12 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
+ goto out;
+ }
+ if (x->calg) {
+- ret = nla_put(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
++ ret = copy_to_user_calg(x->calg, skb);
+ if (ret)
+ goto out;
+ }
+ if (x->encap) {
+- ret = nla_put(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
++ ret = copy_to_user_encap(x->encap, skb);
+ if (ret)
+ goto out;
+ }
+diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
+index 2c80da0220c32..1dfa80c6b471e 100644
+--- a/scripts/mod/modpost.c
++++ b/scripts/mod/modpost.c
+@@ -1722,7 +1722,7 @@ static void extract_crcs_for_object(const char *object, struct module *mod)
+ if (!isdigit(*p))
+ continue; /* skip this line */
+
+- crc = strtol(p, &p, 0);
++ crc = strtoul(p, &p, 0);
+ if (*p != '\n')
+ continue; /* skip this line */
+
+diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
+index 8b6aeb8a78f7d..02fd65993e7e5 100644
+--- a/sound/core/pcm_lib.c
++++ b/sound/core/pcm_lib.c
+@@ -2155,6 +2155,8 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
+ ret = substream->ops->ack(substream);
+ if (ret < 0) {
+ runtime->control->appl_ptr = old_appl_ptr;
++ if (ret == -EPIPE)
++ __snd_pcm_xrun(substream);
+ return ret;
+ }
+ }
+diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c
+index 27e11b5f70b97..c7d7eff86727f 100644
+--- a/sound/pci/asihpi/hpi6205.c
++++ b/sound/pci/asihpi/hpi6205.c
+@@ -430,7 +430,7 @@ void HPI_6205(struct hpi_message *phm, struct hpi_response *phr)
+ pao = hpi_find_adapter(phm->adapter_index);
+ } else {
+ /* subsys messages don't address an adapter */
+- _HPI_6205(NULL, phm, phr);
++ phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
+ return;
+ }
+
+diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
+index acde4cd58785e..099722ebaed83 100644
+--- a/sound/pci/hda/patch_ca0132.c
++++ b/sound/pci/hda/patch_ca0132.c
+@@ -4228,8 +4228,10 @@ static int tuning_ctl_set(struct hda_codec *codec, hda_nid_t nid,
+
+ for (i = 0; i < TUNING_CTLS_COUNT; i++)
+ if (nid == ca0132_tuning_ctls[i].nid)
+- break;
++ goto found;
+
++ return -EINVAL;
++found:
+ snd_hda_power_up(codec);
+ dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20,
+ ca0132_tuning_ctls[i].req,
+diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
+index 75e1d00074b9f..a889cccdd607c 100644
+--- a/sound/pci/hda/patch_conexant.c
++++ b/sound/pci/hda/patch_conexant.c
+@@ -980,7 +980,10 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
+ SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
+- SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_PINCFG_LENOVO_NOTEBOOK),
++ /* NOTE: we'd need to extend the quirk for 17aa:3977 as the same
++ * PCI SSID is used on multiple Lenovo models
++ */
++ SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
+@@ -1003,6 +1006,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
+ { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
+ { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
+ { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
++ { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" },
+ {}
+ };
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 28ac6c159b2a2..070150bbd3559 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -2631,6 +2631,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
++ SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+@@ -2651,6 +2652,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
++ SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+ SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
+@@ -9574,6 +9576,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1558, 0x5101, "Clevo S510WU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x5157, "Clevo W517GU1", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x51a1, "Clevo NS50MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+@@ -9608,6 +9611,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL5[03]RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL50NU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1558, 0xa671, "Clevo NP70SN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0xb022, "Clevo NH77D[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+@@ -9708,6 +9712,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
++ SND_PCI_QUIRK(0x17aa, 0x9e56, "Lenovo ZhaoYang CF4620Z", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
+ SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
+diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
+index 1e198e4d57b8d..82d4e0fda91be 100644
+--- a/sound/pci/ymfpci/ymfpci.c
++++ b/sound/pci/ymfpci/ymfpci.c
+@@ -170,7 +170,7 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
+ return -ENOENT;
+ }
+
+- err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
++ err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
+ sizeof(*chip), &card);
+ if (err < 0)
+ return err;
+diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
+index c80114c0ad7bf..b492c32ce0704 100644
+--- a/sound/pci/ymfpci/ymfpci_main.c
++++ b/sound/pci/ymfpci/ymfpci_main.c
+@@ -2165,7 +2165,7 @@ static int snd_ymfpci_memalloc(struct snd_ymfpci *chip)
+ chip->work_base = ptr;
+ chip->work_base_addr = ptr_addr;
+
+- snd_BUG_ON(ptr + chip->work_size !=
++ snd_BUG_ON(ptr + PAGE_ALIGN(chip->work_size) !=
+ chip->work_ptr->area + chip->work_ptr->bytes);
+
+ snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr);
+diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
+index 5d1c58df081ac..e5611f655beda 100644
+--- a/sound/soc/codecs/lpass-tx-macro.c
++++ b/sound/soc/codecs/lpass-tx-macro.c
+@@ -241,7 +241,7 @@ enum {
+
+ struct tx_mute_work {
+ struct tx_macro *tx;
+- u32 decimator;
++ u8 decimator;
+ struct delayed_work dwork;
+ };
+
+@@ -634,7 +634,7 @@ exit:
+ return 0;
+ }
+
+-static bool is_amic_enabled(struct snd_soc_component *component, int decimator)
++static bool is_amic_enabled(struct snd_soc_component *component, u8 decimator)
+ {
+ u16 adc_mux_reg, adc_reg, adc_n;
+
+@@ -845,7 +845,7 @@ static int tx_macro_enable_dec(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+ {
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+- unsigned int decimator;
++ u8 decimator;
+ u16 tx_vol_ctl_reg, dec_cfg_reg, hpf_gate_reg, tx_gain_ctl_reg;
+ u8 hpf_cut_off_freq;
+ int hpf_delay = TX_MACRO_DMIC_HPF_DELAY_MS;
+@@ -1060,7 +1060,8 @@ static int tx_macro_hw_params(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+ {
+ struct snd_soc_component *component = dai->component;
+- u32 decimator, sample_rate;
++ u32 sample_rate;
++ u8 decimator;
+ int tx_fs_rate;
+ struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+
+@@ -1124,7 +1125,7 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
+ {
+ struct snd_soc_component *component = dai->component;
+ struct tx_macro *tx = snd_soc_component_get_drvdata(component);
+- u16 decimator;
++ u8 decimator;
+
+ /* active decimator not set yet */
+ if (tx->active_decimator[dai->id] == -1)
+diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
+index 02ae542ad7792..a63563594b4cd 100644
+--- a/sound/soc/intel/avs/boards/da7219.c
++++ b/sound/soc/intel/avs/boards/da7219.c
+@@ -111,6 +111,26 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
+ return 0;
+ }
+
++static int
++avs_da7219_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
++{
++ struct snd_interval *rate, *channels;
++ struct snd_mask *fmt;
++
++ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
++ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
++ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
++
++ /* The ADSP will convert the FE rate to 48k, stereo */
++ rate->min = rate->max = 48000;
++ channels->min = channels->max = 2;
++
++ /* set SSP0 to 24 bit */
++ snd_mask_none(fmt);
++ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
++ return 0;
++}
++
+ static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+ {
+@@ -142,6 +162,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
++ dl->be_hw_params_fixup = avs_da7219_be_fixup;
+ dl->init = avs_da7219_codec_init;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
+index 921f42caf7e09..183123d08c5a3 100644
+--- a/sound/soc/intel/avs/boards/max98357a.c
++++ b/sound/soc/intel/avs/boards/max98357a.c
+@@ -8,6 +8,7 @@
+
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
++#include <sound/pcm_params.h>
+ #include <sound/soc.h>
+ #include <sound/soc-acpi.h>
+ #include <sound/soc-dapm.h>
+@@ -24,6 +25,26 @@ static const struct snd_soc_dapm_route card_base_routes[] = {
+ { "Spk", NULL, "Speaker" },
+ };
+
++static int
++avs_max98357a_be_fixup(struct snd_soc_pcm_runtime *runrime, struct snd_pcm_hw_params *params)
++{
++ struct snd_interval *rate, *channels;
++ struct snd_mask *fmt;
++
++ rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
++ channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
++ fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
++
++ /* The ADSP will convert the FE rate to 48k, stereo */
++ rate->min = rate->max = 48000;
++ channels->min = channels->max = 2;
++
++ /* set SSP0 to 16 bit */
++ snd_mask_none(fmt);
++ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
++ return 0;
++}
++
+ static int avs_create_dai_link(struct device *dev, const char *platform_name, int ssp_port,
+ struct snd_soc_dai_link **dai_link)
+ {
+@@ -55,6 +76,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
+ dl->num_platforms = 1;
+ dl->id = 0;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
++ dl->be_hw_params_fixup = avs_max98357a_be_fixup;
+ dl->nonatomic = 1;
+ dl->no_pcm = 1;
+ dl->dpcm_playback = 1;
+diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
+index f76909e9f990a..8392d8fac8f9c 100644
+--- a/sound/soc/intel/avs/boards/nau8825.c
++++ b/sound/soc/intel/avs/boards/nau8825.c
+@@ -33,15 +33,15 @@ avs_nau8825_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *co
+ return -EINVAL;
+ }
+
+- if (!SND_SOC_DAPM_EVENT_ON(event)) {
++ if (SND_SOC_DAPM_EVENT_ON(event))
++ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000,
++ SND_SOC_CLOCK_IN);
++ else
+ ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+- if (ret < 0) {
+- dev_err(card->dev, "set sysclk err = %d\n", ret);
+- return ret;
+- }
+- }
++ if (ret < 0)
++ dev_err(card->dev, "Set sysclk failed: %d\n", ret);
+
+- return 0;
++ return ret;
+ }
+
+ static const struct snd_kcontrol_new card_controls[] = {
+diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
+index 9f84c8ab34478..51a8867326b47 100644
+--- a/sound/soc/intel/avs/boards/ssm4567.c
++++ b/sound/soc/intel/avs/boards/ssm4567.c
+@@ -15,7 +15,6 @@
+ #include <sound/soc-acpi.h>
+ #include "../../../codecs/nau8825.h"
+
+-#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
+ #define SKL_SSM_CODEC_DAI "ssm4567-hifi"
+
+ static struct snd_soc_codec_conf card_codec_conf[] = {
+@@ -34,41 +33,11 @@ static const struct snd_kcontrol_new card_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Right Speaker"),
+ };
+
+-static int
+-platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *control, int event)
+-{
+- struct snd_soc_dapm_context *dapm = w->dapm;
+- struct snd_soc_card *card = dapm->card;
+- struct snd_soc_dai *codec_dai;
+- int ret;
+-
+- codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI);
+- if (!codec_dai) {
+- dev_err(card->dev, "Codec dai not found\n");
+- return -EINVAL;
+- }
+-
+- if (SND_SOC_DAPM_EVENT_ON(event)) {
+- ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_MCLK, 24000000,
+- SND_SOC_CLOCK_IN);
+- if (ret < 0)
+- dev_err(card->dev, "set sysclk err = %d\n", ret);
+- } else {
+- ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
+- if (ret < 0)
+- dev_err(card->dev, "set sysclk err = %d\n", ret);
+- }
+-
+- return ret;
+-}
+-
+ static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_SPK("Left Speaker", NULL),
+ SND_SOC_DAPM_SPK("Right Speaker", NULL),
+ SND_SOC_DAPM_SPK("DP1", NULL),
+ SND_SOC_DAPM_SPK("DP2", NULL),
+- SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control,
+- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ };
+
+ static const struct snd_soc_dapm_route card_base_routes[] = {
+diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c
+index f0f6d9ba88037..0b17d1bb225e2 100644
+--- a/sound/soc/sof/intel/pci-tng.c
++++ b/sound/soc/sof/intel/pci-tng.c
+@@ -75,11 +75,7 @@ static int tangier_pci_probe(struct snd_sof_dev *sdev)
+
+ /* LPE base */
+ base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET;
+- size = pci_resource_len(pci, desc->resindex_lpe_base);
+- if (size < PCI_BAR_SIZE) {
+- dev_err(sdev->dev, "error: I/O region is too small.\n");
+- return -ENODEV;
+- }
++ size = PCI_BAR_SIZE;
+
+ dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size);
+ sdev->bar[DSP_BAR] = devm_ioremap(sdev->dev, base, size);
+diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
+index b28af3a48b707..60b96b0c2412f 100644
+--- a/sound/soc/sof/ipc3.c
++++ b/sound/soc/sof/ipc3.c
+@@ -970,8 +970,9 @@ static void sof_ipc3_rx_msg(struct snd_sof_dev *sdev)
+ return;
+ }
+
+- if (hdr.size < sizeof(hdr)) {
+- dev_err(sdev->dev, "The received message size is invalid\n");
++ if (hdr.size < sizeof(hdr) || hdr.size > SOF_IPC_MSG_MAX_SIZE) {
++ dev_err(sdev->dev, "The received message size is invalid: %u\n",
++ hdr.size);
+ return;
+ }
+
+diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
+index 0d5a578c34962..7442ec1c5a4d4 100644
+--- a/sound/soc/sof/ipc4-control.c
++++ b/sound/soc/sof/ipc4-control.c
+@@ -84,7 +84,8 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge
+ }
+
+ /* set curve type and duration from topology */
+- data.curve_duration = gain->data.curve_duration;
++ data.curve_duration_l = gain->data.curve_duration_l;
++ data.curve_duration_h = gain->data.curve_duration_h;
+ data.curve_type = gain->data.curve_type;
+
+ msg->data_ptr = &data;
+diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
+index a81af5f73a4b4..49289932ba7e6 100644
+--- a/sound/soc/sof/ipc4-topology.c
++++ b/sound/soc/sof/ipc4-topology.c
+@@ -106,7 +106,7 @@ static const struct sof_topology_token gain_tokens[] = {
+ get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
+ {SOF_TKN_GAIN_RAMP_DURATION,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+- offsetof(struct sof_ipc4_gain_data, curve_duration)},
++ offsetof(struct sof_ipc4_gain_data, curve_duration_l)},
+ {SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
+ };
+@@ -154,7 +154,7 @@ static void sof_ipc4_dbg_audio_format(struct device *dev,
+ for (i = 0; i < num_format; i++, ptr = (u8 *)ptr + object_size) {
+ fmt = ptr;
+ dev_dbg(dev,
+- " #%d: %uKHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n",
++ " #%d: %uHz, %ubit (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x)\n",
+ i, fmt->sampling_frequency, fmt->bit_depth, fmt->ch_map,
+ fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg);
+ }
+@@ -682,7 +682,7 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
+
+ dev_dbg(scomp->dev,
+ "pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
+- swidget->widget->name, gain->data.curve_type, gain->data.curve_duration,
++ swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l,
+ gain->data.init_val, gain->base_config.cpc);
+
+ ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
+diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
+index 2363a7cc0b57d..cf9d278524572 100644
+--- a/sound/soc/sof/ipc4-topology.h
++++ b/sound/soc/sof/ipc4-topology.h
+@@ -217,14 +217,16 @@ struct sof_ipc4_control_data {
+ * @init_val: Initial value
+ * @curve_type: Curve type
+ * @reserved: reserved for future use
+- * @curve_duration: Curve duration
++ * @curve_duration_l: Curve duration low part
++ * @curve_duration_h: Curve duration high part
+ */
+ struct sof_ipc4_gain_data {
+ uint32_t channels;
+ uint32_t init_val;
+ uint32_t curve_type;
+ uint32_t reserved;
+- uint32_t curve_duration;
++ uint32_t curve_duration_l;
++ uint32_t curve_duration_h;
+ } __aligned(8);
+
+ /**
+diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
+index 419302e2057e8..647fa054d8b1d 100644
+--- a/sound/usb/endpoint.c
++++ b/sound/usb/endpoint.c
+@@ -455,8 +455,8 @@ static void push_back_to_ready_list(struct snd_usb_endpoint *ep,
+ * This function is used both for implicit feedback endpoints and in low-
+ * latency playback mode.
+ */
+-void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
+- bool in_stream_lock)
++int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
++ bool in_stream_lock)
+ {
+ bool implicit_fb = snd_usb_endpoint_implicit_feedback_sink(ep);
+
+@@ -480,7 +480,7 @@ void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ if (ctx == NULL)
+- return;
++ break;
+
+ /* copy over the length information */
+ if (implicit_fb) {
+@@ -495,11 +495,14 @@ void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
+ break;
+ if (err < 0) {
+ /* push back to ready list again for -EAGAIN */
+- if (err == -EAGAIN)
++ if (err == -EAGAIN) {
+ push_back_to_ready_list(ep, ctx);
+- else
++ break;
++ }
++
++ if (!in_stream_lock)
+ notify_xrun(ep);
+- return;
++ return -EPIPE;
+ }
+
+ err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
+@@ -507,13 +510,16 @@ void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
+ usb_audio_err(ep->chip,
+ "Unable to submit urb #%d: %d at %s\n",
+ ctx->index, err, __func__);
+- notify_xrun(ep);
+- return;
++ if (!in_stream_lock)
++ notify_xrun(ep);
++ return -EPIPE;
+ }
+
+ set_bit(ctx->index, &ep->active_mask);
+ atomic_inc(&ep->submitted_urbs);
+ }
++
++ return 0;
+ }
+
+ /*
+diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
+index 924f4351588ce..c09f68ce08b18 100644
+--- a/sound/usb/endpoint.h
++++ b/sound/usb/endpoint.h
+@@ -52,7 +52,7 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
+ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *ctx, int idx,
+ unsigned int avail);
+-void snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
+- bool in_stream_lock);
++int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep,
++ bool in_stream_lock);
+
+ #endif /* __USBAUDIO_ENDPOINT_H */
+diff --git a/sound/usb/format.c b/sound/usb/format.c
+index 405dc0bf6678c..4b1c5ba121f39 100644
+--- a/sound/usb/format.c
++++ b/sound/usb/format.c
+@@ -39,8 +39,12 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
+ case UAC_VERSION_1:
+ default: {
+ struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
+- if (format >= 64)
+- return 0; /* invalid format */
++ if (format >= 64) {
++ usb_audio_info(chip,
++ "%u:%d: invalid format type 0x%llx is detected, processed as PCM\n",
++ fp->iface, fp->altsetting, format);
++ format = UAC_FORMAT_TYPE_I_PCM;
++ }
+ sample_width = fmt->bBitResolution;
+ sample_bytes = fmt->bSubframeSize;
+ format = 1ULL << format;
+diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
+index 2c5765cbed2d6..1e1d7458bce10 100644
+--- a/sound/usb/pcm.c
++++ b/sound/usb/pcm.c
+@@ -1595,7 +1595,7 @@ static int snd_usb_pcm_playback_ack(struct snd_pcm_substream *substream)
+ * outputs here
+ */
+ if (!ep->active_mask)
+- snd_usb_queue_pending_output_urbs(ep, true);
++ return snd_usb_queue_pending_output_urbs(ep, true);
+ return 0;
+ }
+
+diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
+index 0b470169729e6..56102711f395a 100644
+--- a/tools/lib/bpf/btf_dump.c
++++ b/tools/lib/bpf/btf_dump.c
+@@ -833,14 +833,9 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
+ const struct btf_type *t)
+ {
+ const struct btf_member *m;
+- int align, i, bit_sz;
++ int max_align = 1, align, i, bit_sz;
+ __u16 vlen;
+
+- align = btf__align_of(btf, id);
+- /* size of a non-packed struct has to be a multiple of its alignment*/
+- if (align && t->size % align)
+- return true;
+-
+ m = btf_members(t);
+ vlen = btf_vlen(t);
+ /* all non-bitfield fields have to be naturally aligned */
+@@ -849,8 +844,11 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
+ bit_sz = btf_member_bitfield_size(t, i);
+ if (align && bit_sz == 0 && m->offset % (8 * align) != 0)
+ return true;
++ max_align = max(align, max_align);
+ }
+-
++ /* size of a non-packed struct has to be a multiple of its alignment */
++ if (t->size % max_align != 0)
++ return true;
+ /*
+ * if original struct was marked as packed, but its layout is
+ * naturally aligned, we'll detect that it's not packed
+@@ -858,44 +856,97 @@ static bool btf_is_struct_packed(const struct btf *btf, __u32 id,
+ return false;
+ }
+
+-static int chip_away_bits(int total, int at_most)
+-{
+- return total % at_most ? : at_most;
+-}
+-
+ static void btf_dump_emit_bit_padding(const struct btf_dump *d,
+- int cur_off, int m_off, int m_bit_sz,
+- int align, int lvl)
++ int cur_off, int next_off, int next_align,
++ bool in_bitfield, int lvl)
+ {
+- int off_diff = m_off - cur_off;
+- int ptr_bits = d->ptr_sz * 8;
++ const struct {
++ const char *name;
++ int bits;
++ } pads[] = {
++ {"long", d->ptr_sz * 8}, {"int", 32}, {"short", 16}, {"char", 8}
++ };
++ int new_off, pad_bits, bits, i;
++ const char *pad_type;
++
++ if (cur_off >= next_off)
++ return; /* no gap */
++
++ /* For filling out padding we want to take advantage of
++ * natural alignment rules to minimize unnecessary explicit
++ * padding. First, we find the largest type (among long, int,
++ * short, or char) that can be used to force naturally aligned
++ * boundary. Once determined, we'll use such type to fill in
++ * the remaining padding gap. In some cases we can rely on
++ * compiler filling some gaps, but sometimes we need to force
++ * alignment to close natural alignment with markers like
++ * `long: 0` (this is always the case for bitfields). Note
++ * that even if struct itself has, let's say 4-byte alignment
++ * (i.e., it only uses up to int-aligned types), using `long:
++ * X;` explicit padding doesn't actually change struct's
++ * overall alignment requirements, but compiler does take into
++ * account that type's (long, in this example) natural
++ * alignment requirements when adding implicit padding. We use
++ * this fact heavily and don't worry about ruining correct
++ * struct alignment requirement.
++ */
++ for (i = 0; i < ARRAY_SIZE(pads); i++) {
++ pad_bits = pads[i].bits;
++ pad_type = pads[i].name;
+
+- if (off_diff <= 0)
+- /* no gap */
+- return;
+- if (m_bit_sz == 0 && off_diff < align * 8)
+- /* natural padding will take care of a gap */
+- return;
++ new_off = roundup(cur_off, pad_bits);
++ if (new_off <= next_off)
++ break;
++ }
+
+- while (off_diff > 0) {
+- const char *pad_type;
+- int pad_bits;
+-
+- if (ptr_bits > 32 && off_diff > 32) {
+- pad_type = "long";
+- pad_bits = chip_away_bits(off_diff, ptr_bits);
+- } else if (off_diff > 16) {
+- pad_type = "int";
+- pad_bits = chip_away_bits(off_diff, 32);
+- } else if (off_diff > 8) {
+- pad_type = "short";
+- pad_bits = chip_away_bits(off_diff, 16);
+- } else {
+- pad_type = "char";
+- pad_bits = chip_away_bits(off_diff, 8);
++ if (new_off > cur_off && new_off <= next_off) {
++ /* We need explicit `<type>: 0` aligning mark if next
++ * field is right on alignment offset and its
++ * alignment requirement is less strict than <type>'s
++ * alignment (so compiler won't naturally align to the
++ * offset we expect), or if subsequent `<type>: X`,
++ * will actually completely fit in the remaining hole,
++ * making compiler basically ignore `<type>: X`
++ * completely.
++ */
++ if (in_bitfield ||
++ (new_off == next_off && roundup(cur_off, next_align * 8) != new_off) ||
++ (new_off != next_off && next_off - new_off <= new_off - cur_off))
++ /* but for bitfields we'll emit explicit bit count */
++ btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type,
++ in_bitfield ? new_off - cur_off : 0);
++ cur_off = new_off;
++ }
++
++ /* Now we know we start at naturally aligned offset for a chosen
++ * padding type (long, int, short, or char), and so the rest is just
++ * a straightforward filling of remaining padding gap with full
++ * `<type>: sizeof(<type>);` markers, except for the last one, which
++ * might need smaller than sizeof(<type>) padding.
++ */
++ while (cur_off != next_off) {
++ bits = min(next_off - cur_off, pad_bits);
++ if (bits == pad_bits) {
++ btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
++ cur_off += bits;
++ continue;
++ }
++ /* For the remainder padding that doesn't cover entire
++ * pad_type bit length, we pick the smallest necessary type.
++ * This is pure aesthetics, we could have just used `long`,
++ * but having smallest necessary one communicates better the
++ * scale of the padding gap.
++ */
++ for (i = ARRAY_SIZE(pads) - 1; i >= 0; i--) {
++ pad_type = pads[i].name;
++ pad_bits = pads[i].bits;
++ if (pad_bits < bits)
++ continue;
++
++ btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, bits);
++ cur_off += bits;
++ break;
+ }
+- btf_dump_printf(d, "\n%s%s: %d;", pfx(lvl), pad_type, pad_bits);
+- off_diff -= pad_bits;
+ }
+ }
+
+@@ -915,9 +966,11 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
+ {
+ const struct btf_member *m = btf_members(t);
+ bool is_struct = btf_is_struct(t);
+- int align, i, packed, off = 0;
++ bool packed, prev_bitfield = false;
++ int align, i, off = 0;
+ __u16 vlen = btf_vlen(t);
+
++ align = btf__align_of(d->btf, id);
+ packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0;
+
+ btf_dump_printf(d, "%s%s%s {",
+@@ -927,33 +980,36 @@ static void btf_dump_emit_struct_def(struct btf_dump *d,
+
+ for (i = 0; i < vlen; i++, m++) {
+ const char *fname;
+- int m_off, m_sz;
++ int m_off, m_sz, m_align;
++ bool in_bitfield;
+
+ fname = btf_name_of(d, m->name_off);
+ m_sz = btf_member_bitfield_size(t, i);
+ m_off = btf_member_bit_offset(t, i);
+- align = packed ? 1 : btf__align_of(d->btf, m->type);
++ m_align = packed ? 1 : btf__align_of(d->btf, m->type);
+
+- btf_dump_emit_bit_padding(d, off, m_off, m_sz, align, lvl + 1);
++ in_bitfield = prev_bitfield && m_sz != 0;
++
++ btf_dump_emit_bit_padding(d, off, m_off, m_align, in_bitfield, lvl + 1);
+ btf_dump_printf(d, "\n%s", pfx(lvl + 1));
+ btf_dump_emit_type_decl(d, m->type, fname, lvl + 1);
+
+ if (m_sz) {
+ btf_dump_printf(d, ": %d", m_sz);
+ off = m_off + m_sz;
++ prev_bitfield = true;
+ } else {
+ m_sz = max((__s64)0, btf__resolve_size(d->btf, m->type));
+ off = m_off + m_sz * 8;
++ prev_bitfield = false;
+ }
++
+ btf_dump_printf(d, ";");
+ }
+
+ /* pad at the end, if necessary */
+- if (is_struct) {
+- align = packed ? 1 : btf__align_of(d->btf, id);
+- btf_dump_emit_bit_padding(d, off, t->size * 8, 0, align,
+- lvl + 1);
+- }
++ if (is_struct)
++ btf_dump_emit_bit_padding(d, off, t->size * 8, align, false, lvl + 1);
+
+ if (vlen)
+ btf_dump_printf(d, "\n");
+diff --git a/tools/power/acpi/tools/pfrut/pfrut.c b/tools/power/acpi/tools/pfrut/pfrut.c
+index 52aa0351533c3..388c9e3ad0407 100644
+--- a/tools/power/acpi/tools/pfrut/pfrut.c
++++ b/tools/power/acpi/tools/pfrut/pfrut.c
+@@ -97,7 +97,7 @@ static struct option long_options[] = {
+ static void parse_options(int argc, char **argv)
+ {
+ int option_index = 0;
+- char *pathname;
++ char *pathname, *endptr;
+ int opt;
+
+ pathname = strdup(argv[0]);
+@@ -125,11 +125,23 @@ static void parse_options(int argc, char **argv)
+ log_getinfo = 1;
+ break;
+ case 'T':
+- log_type = atoi(optarg);
++ log_type = strtol(optarg, &endptr, 0);
++ if (*endptr || (log_type != 0 && log_type != 1)) {
++ printf("Number expected: type(0:execution, 1:history) - Quit.\n");
++ exit(1);
++ }
++
+ set_log_type = 1;
+ break;
+ case 'L':
+- log_level = atoi(optarg);
++ log_level = strtol(optarg, &endptr, 0);
++ if (*endptr ||
++ (log_level != 0 && log_level != 1 &&
++ log_level != 2 && log_level != 4)) {
++ printf("Number expected: level(0, 1, 2, 4) - Quit.\n");
++ exit(1);
++ }
++
+ set_log_level = 1;
+ break;
+ case 'R':
+diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
+index c7b26a3603afe..3e1a4c4be001a 100644
+--- a/tools/power/x86/turbostat/turbostat.8
++++ b/tools/power/x86/turbostat/turbostat.8
+@@ -344,6 +344,8 @@ Alternatively, non-root users can be enabled to run turbostat this way:
+
+ # chmod +r /dev/cpu/*/msr
+
++# chmod +r /dev/cpu_dma_latency
++
+ .B "turbostat "
+ reads hardware counters, but doesn't write them.
+ So it will not interfere with the OS or other programs, including
+diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
+index aba460410dbd1..c61c6c704fbe6 100644
+--- a/tools/power/x86/turbostat/turbostat.c
++++ b/tools/power/x86/turbostat/turbostat.c
+@@ -4426,7 +4426,7 @@ int print_hwp(struct thread_data *t, struct core_data *c, struct pkg_data *p)
+
+ fprintf(outf, "cpu%d: MSR_HWP_STATUS: 0x%08llx "
+ "(%sGuaranteed_Perf_Change, %sExcursion_Min)\n",
+- cpu, msr, ((msr) & 0x1) ? "" : "No-", ((msr) & 0x2) ? "" : "No-");
++ cpu, msr, ((msr) & 0x1) ? "" : "No-", ((msr) & 0x4) ? "" : "No-");
+
+ return 0;
+ }
+@@ -5482,7 +5482,7 @@ void print_dev_latency(void)
+
+ retval = read(fd, (void *)&value, sizeof(int));
+ if (retval != sizeof(int)) {
+- warn("read %s\n", path);
++ warn("read failed %s\n", path);
+ close(fd);
+ return;
+ }
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c
+index e5560a6560309..e01690618e1ee 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_bitfields.c
+@@ -53,7 +53,7 @@ struct bitfields_only_mixed_types {
+ */
+ /* ------ END-EXPECTED-OUTPUT ------ */
+ struct bitfield_mixed_with_others {
+- long: 4; /* char is enough as a backing field */
++ char: 4; /* char is enough as a backing field */
+ int a: 4;
+ /* 8-bit implicit padding */
+ short b; /* combined with previous bitfield */
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
+index e304b6204bd9d..7998f27df7ddd 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_packing.c
+@@ -58,7 +58,81 @@ union jump_code_union {
+ } __attribute__((packed));
+ };
+
+-/*------ END-EXPECTED-OUTPUT ------ */
++/* ----- START-EXPECTED-OUTPUT ----- */
++/*
++ *struct nested_packed_but_aligned_struct {
++ * int x1;
++ * int x2;
++ *};
++ *
++ *struct outer_implicitly_packed_struct {
++ * char y1;
++ * struct nested_packed_but_aligned_struct y2;
++ *} __attribute__((packed));
++ *
++ */
++/* ------ END-EXPECTED-OUTPUT ------ */
++
++struct nested_packed_but_aligned_struct {
++ int x1;
++ int x2;
++} __attribute__((packed));
++
++struct outer_implicitly_packed_struct {
++ char y1;
++ struct nested_packed_but_aligned_struct y2;
++};
++/* ----- START-EXPECTED-OUTPUT ----- */
++/*
++ *struct usb_ss_ep_comp_descriptor {
++ * char: 8;
++ * char bDescriptorType;
++ * char bMaxBurst;
++ * short wBytesPerInterval;
++ *};
++ *
++ *struct usb_host_endpoint {
++ * long: 64;
++ * char: 8;
++ * struct usb_ss_ep_comp_descriptor ss_ep_comp;
++ * long: 0;
++ *} __attribute__((packed));
++ *
++ */
++/* ------ END-EXPECTED-OUTPUT ------ */
++
++struct usb_ss_ep_comp_descriptor {
++ char: 8;
++ char bDescriptorType;
++ char bMaxBurst;
++ int: 0;
++ short wBytesPerInterval;
++} __attribute__((packed));
++
++struct usb_host_endpoint {
++ long: 64;
++ char: 8;
++ struct usb_ss_ep_comp_descriptor ss_ep_comp;
++ long: 0;
++};
++
++/* ----- START-EXPECTED-OUTPUT ----- */
++struct nested_packed_struct {
++ int a;
++ char b;
++} __attribute__((packed));
++
++struct outer_nonpacked_struct {
++ short a;
++ struct nested_packed_struct b;
++};
++
++struct outer_packed_struct {
++ short a;
++ struct nested_packed_struct b;
++} __attribute__((packed));
++
++/* ------ END-EXPECTED-OUTPUT ------ */
+
+ int f(struct {
+ struct packed_trailing_space _1;
+@@ -69,6 +143,10 @@ int f(struct {
+ union union_is_never_packed _6;
+ union union_does_not_need_packing _7;
+ union jump_code_union _8;
++ struct outer_implicitly_packed_struct _9;
++ struct usb_host_endpoint _10;
++ struct outer_nonpacked_struct _11;
++ struct outer_packed_struct _12;
+ } *_)
+ {
+ return 0;
+diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
+index f2661c8d2d900..79276fbe454a8 100644
+--- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
++++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c
+@@ -19,7 +19,7 @@ struct padded_implicitly {
+ /*
+ *struct padded_explicitly {
+ * int a;
+- * int: 32;
++ * long: 0;
+ * int b;
+ *};
+ *
+@@ -28,41 +28,28 @@ struct padded_implicitly {
+
+ struct padded_explicitly {
+ int a;
+- int: 1; /* algo will explicitly pad with full 32 bits here */
++ int: 1; /* algo will emit aligning `long: 0;` here */
+ int b;
+ };
+
+ /* ----- START-EXPECTED-OUTPUT ----- */
+-/*
+- *struct padded_a_lot {
+- * int a;
+- * long: 32;
+- * long: 64;
+- * long: 64;
+- * int b;
+- *};
+- *
+- */
+-/* ------ END-EXPECTED-OUTPUT ------ */
+-
+ struct padded_a_lot {
+ int a;
+- /* 32 bit of implicit padding here, which algo will make explicit */
+ long: 64;
+ long: 64;
+ int b;
+ };
+
++/* ------ END-EXPECTED-OUTPUT ------ */
++
+ /* ----- START-EXPECTED-OUTPUT ----- */
+ /*
+ *struct padded_cache_line {
+ * int a;
+- * long: 32;
+ * long: 64;
+ * long: 64;
+ * long: 64;
+ * int b;
+- * long: 32;
+ * long: 64;
+ * long: 64;
+ * long: 64;
+@@ -85,7 +72,7 @@ struct padded_cache_line {
+ *struct zone {
+ * int a;
+ * short b;
+- * short: 16;
++ * long: 0;
+ * struct zone_padding __pad__;
+ *};
+ *
+@@ -102,12 +89,160 @@ struct zone {
+ struct zone_padding __pad__;
+ };
+
++/* ----- START-EXPECTED-OUTPUT ----- */
++struct padding_wo_named_members {
++ long: 64;
++ long: 64;
++};
++
++struct padding_weird_1 {
++ int a;
++ long: 64;
++ short: 16;
++ short b;
++};
++
++/* ------ END-EXPECTED-OUTPUT ------ */
++
++/* ----- START-EXPECTED-OUTPUT ----- */
++/*
++ *struct padding_weird_2 {
++ * long: 56;
++ * char a;
++ * long: 56;
++ * char b;
++ * char: 8;
++ *};
++ *
++ */
++/* ------ END-EXPECTED-OUTPUT ------ */
++struct padding_weird_2 {
++ int: 32; /* these paddings will be collapsed into `long: 56;` */
++ short: 16;
++ char: 8;
++ char a;
++ int: 32; /* these paddings will be collapsed into `long: 56;` */
++ short: 16;
++ char: 8;
++ char b;
++ char: 8;
++};
++
++/* ----- START-EXPECTED-OUTPUT ----- */
++struct exact_1byte {
++ char x;
++};
++
++struct padded_1byte {
++ char: 8;
++};
++
++struct exact_2bytes {
++ short x;
++};
++
++struct padded_2bytes {
++ short: 16;
++};
++
++struct exact_4bytes {
++ int x;
++};
++
++struct padded_4bytes {
++ int: 32;
++};
++
++struct exact_8bytes {
++ long x;
++};
++
++struct padded_8bytes {
++ long: 64;
++};
++
++struct ff_periodic_effect {
++ int: 32;
++ short magnitude;
++ long: 0;
++ short phase;
++ long: 0;
++ int: 32;
++ int custom_len;
++ short *custom_data;
++};
++
++struct ib_wc {
++ long: 64;
++ long: 64;
++ int: 32;
++ int byte_len;
++ void *qp;
++ union {} ex;
++ long: 64;
++ int slid;
++ int wc_flags;
++ long: 64;
++ char smac[6];
++ long: 0;
++ char network_hdr_type;
++};
++
++struct acpi_object_method {
++ long: 64;
++ char: 8;
++ char type;
++ short reference_count;
++ char flags;
++ short: 0;
++ char: 8;
++ char sync_level;
++ long: 64;
++ void *node;
++ void *aml_start;
++ union {} dispatch;
++ long: 64;
++ int aml_length;
++};
++
++struct nested_unpacked {
++ int x;
++};
++
++struct nested_packed {
++ struct nested_unpacked a;
++ char c;
++} __attribute__((packed));
++
++struct outer_mixed_but_unpacked {
++ struct nested_packed b1;
++ short a1;
++ struct nested_packed b2;
++};
++
++/* ------ END-EXPECTED-OUTPUT ------ */
++
+ int f(struct {
+ struct padded_implicitly _1;
+ struct padded_explicitly _2;
+ struct padded_a_lot _3;
+ struct padded_cache_line _4;
+ struct zone _5;
++ struct padding_wo_named_members _6;
++ struct padding_weird_1 _7;
++ struct padding_weird_2 _8;
++ struct exact_1byte _100;
++ struct padded_1byte _101;
++ struct exact_2bytes _102;
++ struct padded_2bytes _103;
++ struct exact_4bytes _104;
++ struct padded_4bytes _105;
++ struct exact_8bytes _106;
++ struct padded_8bytes _107;
++ struct ff_periodic_effect _200;
++ struct ib_wc _201;
++ struct acpi_object_method _202;
++ struct outer_mixed_but_unpacked _203;
+ } *_)
+ {
+ return 0;