public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Arisu Tachibana" <alicef@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/linux-patches:6.16 commit in: /
Date: Sat, 20 Sep 2025 05:25:34 +0000 (UTC)	[thread overview]
Message-ID: <1758345920.9ffd46d3a792ef5eb448d3a3fcf684e769b965d5.alicef@gentoo> (raw)

commit:     9ffd46d3a792ef5eb448d3a3fcf684e769b965d5
Author:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
AuthorDate: Sat Sep 20 05:25:20 2025 +0000
Commit:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
CommitDate: Sat Sep 20 05:25:20 2025 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=9ffd46d3

Linux patch 6.16.8

Signed-off-by: Arisu Tachibana <alicef <AT> gentoo.org>

 0000_README                         |     4 +
 1007_linux-6.16.8.patch             | 11381 ++++++++++++++++++++++++++++++++++
 2991_libbpf_add_WERROR_option.patch |    11 -
 3 files changed, 11385 insertions(+), 11 deletions(-)

diff --git a/0000_README b/0000_README
index 33049ae5..fb6f961a 100644
--- a/0000_README
+++ b/0000_README
@@ -71,6 +71,10 @@ Patch:  1006_linux-6.16.7.patch
 From:   https://www.kernel.org
 Desc:   Linux 6.16.7
 
+Patch:  1007_linux-6.16.8.patch
+From:   https://www.kernel.org
+Desc:   Linux 6.16.8
+
 Patch:  1510_fs-enable-link-security-restrictions-by-default.patch
 From:   http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/
 Desc:   Enable link security restrictions by default.

diff --git a/1007_linux-6.16.8.patch b/1007_linux-6.16.8.patch
new file mode 100644
index 00000000..81ef3369
--- /dev/null
+++ b/1007_linux-6.16.8.patch
@@ -0,0 +1,11381 @@
+diff --git a/Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml b/Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml
+index 89c462653e2d33..8cc848ae11cb73 100644
+--- a/Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml
++++ b/Documentation/devicetree/bindings/serial/brcm,bcm7271-uart.yaml
+@@ -41,7 +41,7 @@ properties:
+           - const: dma_intr2
+ 
+   clocks:
+-    minItems: 1
++    maxItems: 1
+ 
+   clock-names:
+     const: sw_baud
+diff --git a/Documentation/netlink/specs/mptcp_pm.yaml b/Documentation/netlink/specs/mptcp_pm.yaml
+index fb57860fe778c6..ecfe5ee33de2d8 100644
+--- a/Documentation/netlink/specs/mptcp_pm.yaml
++++ b/Documentation/netlink/specs/mptcp_pm.yaml
+@@ -256,7 +256,7 @@ attribute-sets:
+         type: u32
+       -
+         name: if-idx
+-        type: u32
++        type: s32
+       -
+         name: reset-reason
+         type: u32
+diff --git a/Documentation/networking/can.rst b/Documentation/networking/can.rst
+index b018ce34639265..515a3876f58cfd 100644
+--- a/Documentation/networking/can.rst
++++ b/Documentation/networking/can.rst
+@@ -742,7 +742,7 @@ The broadcast manager sends responses to user space in the same form:
+             struct timeval ival1, ival2;    /* count and subsequent interval */
+             canid_t can_id;                 /* unique can_id for task */
+             __u32 nframes;                  /* number of can_frames following */
+-            struct can_frame frames[0];
++            struct can_frame frames[];
+     };
+ 
+ The aligned payload 'frames' uses the same basic CAN frame structure defined
+diff --git a/Documentation/networking/mptcp.rst b/Documentation/networking/mptcp.rst
+index 17f2bab6116447..2e31038d646205 100644
+--- a/Documentation/networking/mptcp.rst
++++ b/Documentation/networking/mptcp.rst
+@@ -60,10 +60,10 @@ address announcements. Typically, it is the client side that initiates subflows,
+ and the server side that announces additional addresses via the ``ADD_ADDR`` and
+ ``REMOVE_ADDR`` options.
+ 
+-Path managers are controlled by the ``net.mptcp.pm_type`` sysctl knob -- see
+-mptcp-sysctl.rst. There are two types: the in-kernel one (type ``0``) where the
+-same rules are applied for all the connections (see: ``ip mptcp``) ; and the
+-userspace one (type ``1``), controlled by a userspace daemon (i.e. `mptcpd
++Path managers are controlled by the ``net.mptcp.path_manager`` sysctl knob --
++see mptcp-sysctl.rst. There are two types: the in-kernel one (``kernel``) where
++the same rules are applied for all the connections (see: ``ip mptcp``) ; and the
++userspace one (``userspace``), controlled by a userspace daemon (i.e. `mptcpd
+ <https://mptcpd.mptcp.dev/>`_) where different rules can be applied for each
+ connection. The path managers can be controlled via a Netlink API; see
+ netlink_spec/mptcp_pm.rst.
+diff --git a/Makefile b/Makefile
+index 86359283ccc9a9..7594f35cbc2a5a 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 6
+ PATCHLEVEL = 16
+-SUBLEVEL = 7
++SUBLEVEL = 8
+ EXTRAVERSION =
+ NAME = Baby Opossum Posse
+ 
+diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
+index af1ca875c52ce2..410060ebd86dfd 100644
+--- a/arch/arm64/kernel/machine_kexec_file.c
++++ b/arch/arm64/kernel/machine_kexec_file.c
+@@ -94,7 +94,7 @@ int load_other_segments(struct kimage *image,
+ 			char *initrd, unsigned long initrd_len,
+ 			char *cmdline)
+ {
+-	struct kexec_buf kbuf;
++	struct kexec_buf kbuf = {};
+ 	void *dtb = NULL;
+ 	unsigned long initrd_load_addr = 0, dtb_len,
+ 		      orig_segments = image->nr_segments;
+diff --git a/arch/s390/kernel/kexec_elf.c b/arch/s390/kernel/kexec_elf.c
+index 4d364de4379921..143e34a4eca57c 100644
+--- a/arch/s390/kernel/kexec_elf.c
++++ b/arch/s390/kernel/kexec_elf.c
+@@ -16,7 +16,7 @@
+ static int kexec_file_add_kernel_elf(struct kimage *image,
+ 				     struct s390_load_data *data)
+ {
+-	struct kexec_buf buf;
++	struct kexec_buf buf = {};
+ 	const Elf_Ehdr *ehdr;
+ 	const Elf_Phdr *phdr;
+ 	Elf_Addr entry;
+diff --git a/arch/s390/kernel/kexec_image.c b/arch/s390/kernel/kexec_image.c
+index a32ce8bea745cf..9a439175723cad 100644
+--- a/arch/s390/kernel/kexec_image.c
++++ b/arch/s390/kernel/kexec_image.c
+@@ -16,7 +16,7 @@
+ static int kexec_file_add_kernel_image(struct kimage *image,
+ 				       struct s390_load_data *data)
+ {
+-	struct kexec_buf buf;
++	struct kexec_buf buf = {};
+ 
+ 	buf.image = image;
+ 
+diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c
+index c2bac14dd668ae..a36d7311c6683b 100644
+--- a/arch/s390/kernel/machine_kexec_file.c
++++ b/arch/s390/kernel/machine_kexec_file.c
+@@ -129,7 +129,7 @@ static int kexec_file_update_purgatory(struct kimage *image,
+ static int kexec_file_add_purgatory(struct kimage *image,
+ 				    struct s390_load_data *data)
+ {
+-	struct kexec_buf buf;
++	struct kexec_buf buf = {};
+ 	int ret;
+ 
+ 	buf.image = image;
+@@ -152,7 +152,7 @@ static int kexec_file_add_purgatory(struct kimage *image,
+ static int kexec_file_add_initrd(struct kimage *image,
+ 				 struct s390_load_data *data)
+ {
+-	struct kexec_buf buf;
++	struct kexec_buf buf = {};
+ 	int ret;
+ 
+ 	buf.image = image;
+@@ -184,7 +184,7 @@ static int kexec_file_add_ipl_report(struct kimage *image,
+ {
+ 	__u32 *lc_ipl_parmblock_ptr;
+ 	unsigned int len, ncerts;
+-	struct kexec_buf buf;
++	struct kexec_buf buf = {};
+ 	unsigned long addr;
+ 	void *ptr, *end;
+ 	int ret;
+diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c
+index 6a262e198e35ec..952cc8d103693f 100644
+--- a/arch/s390/kernel/perf_cpum_cf.c
++++ b/arch/s390/kernel/perf_cpum_cf.c
+@@ -761,8 +761,6 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type)
+ 		break;
+ 
+ 	case PERF_TYPE_HARDWARE:
+-		if (is_sampling_event(event))	/* No sampling support */
+-			return -ENOENT;
+ 		ev = attr->config;
+ 		if (!attr->exclude_user && attr->exclude_kernel) {
+ 			/*
+@@ -860,6 +858,8 @@ static int cpumf_pmu_event_init(struct perf_event *event)
+ 	unsigned int type = event->attr.type;
+ 	int err = -ENOENT;
+ 
++	if (is_sampling_event(event))	/* No sampling support */
++		return err;
+ 	if (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_RAW)
+ 		err = __hw_perf_event_init(event, type);
+ 	else if (event->pmu->type == type)
+diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c
+index 63875270941bc4..01cc6493367a46 100644
+--- a/arch/s390/kernel/perf_pai_crypto.c
++++ b/arch/s390/kernel/perf_pai_crypto.c
+@@ -286,10 +286,10 @@ static int paicrypt_event_init(struct perf_event *event)
+ 	/* PAI crypto PMU registered as PERF_TYPE_RAW, check event type */
+ 	if (a->type != PERF_TYPE_RAW && event->pmu->type != a->type)
+ 		return -ENOENT;
+-	/* PAI crypto event must be in valid range */
++	/* PAI crypto event must be in valid range, try others if not */
+ 	if (a->config < PAI_CRYPTO_BASE ||
+ 	    a->config > PAI_CRYPTO_BASE + paicrypt_cnt)
+-		return -EINVAL;
++		return -ENOENT;
+ 	/* Allow only CRYPTO_ALL for sampling */
+ 	if (a->sample_period && a->config != PAI_CRYPTO_BASE)
+ 		return -EINVAL;
+diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c
+index fd14d5ebccbca0..d65a9730753c55 100644
+--- a/arch/s390/kernel/perf_pai_ext.c
++++ b/arch/s390/kernel/perf_pai_ext.c
+@@ -266,7 +266,7 @@ static int paiext_event_valid(struct perf_event *event)
+ 		event->hw.config_base = offsetof(struct paiext_cb, acc);
+ 		return 0;
+ 	}
+-	return -EINVAL;
++	return -ENOENT;
+ }
+ 
+ /* Might be called on different CPU than the one the event is intended for. */
+diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c
+index 827dd0dbb6e9d2..c79ebbb639cbff 100644
+--- a/arch/x86/kernel/cpu/topology_amd.c
++++ b/arch/x86/kernel/cpu/topology_amd.c
+@@ -175,27 +175,30 @@ static void topoext_fixup(struct topo_scan *tscan)
+ 
+ static void parse_topology_amd(struct topo_scan *tscan)
+ {
+-	bool has_topoext = false;
+-
+ 	/*
+-	 * If the extended topology leaf 0x8000_001e is available
+-	 * try to get SMT, CORE, TILE, and DIE shifts from extended
++	 * Try to get SMT, CORE, TILE, and DIE shifts from extended
+ 	 * CPUID leaf 0x8000_0026 on supported processors first. If
+ 	 * extended CPUID leaf 0x8000_0026 is not supported, try to
+-	 * get SMT and CORE shift from leaf 0xb first, then try to
+-	 * get the CORE shift from leaf 0x8000_0008.
++	 * get SMT and CORE shift from leaf 0xb. If either leaf is
++	 * available, cpu_parse_topology_ext() will return true.
+ 	 */
+-	if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
+-		has_topoext = cpu_parse_topology_ext(tscan);
++	bool has_xtopology = cpu_parse_topology_ext(tscan);
+ 
+ 	if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES))
+ 		tscan->c->topo.cpu_type = cpuid_ebx(0x80000026);
+ 
+-	if (!has_topoext && !parse_8000_0008(tscan))
++	/*
++	 * If XTOPOLOGY leaves (0x26/0xb) are not available, try to
++	 * get the CORE shift from leaf 0x8000_0008 first.
++	 */
++	if (!has_xtopology && !parse_8000_0008(tscan))
+ 		return;
+ 
+-	/* Prefer leaf 0x8000001e if available */
+-	if (parse_8000_001e(tscan, has_topoext))
++	/*
++	 * Prefer leaf 0x8000001e if available to get the SMT shift and
++	 * the initial APIC ID if XTOPOLOGY leaves are not available.
++	 */
++	if (parse_8000_001e(tscan, has_xtopology))
+ 		return;
+ 
+ 	/* Try the NODEID MSR */
+diff --git a/block/fops.c b/block/fops.c
+index 1309861d4c2c4b..d62fbefb2e6712 100644
+--- a/block/fops.c
++++ b/block/fops.c
+@@ -7,6 +7,7 @@
+ #include <linux/init.h>
+ #include <linux/mm.h>
+ #include <linux/blkdev.h>
++#include <linux/blk-integrity.h>
+ #include <linux/buffer_head.h>
+ #include <linux/mpage.h>
+ #include <linux/uio.h>
+@@ -54,7 +55,6 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
+ 	struct bio bio;
+ 	ssize_t ret;
+ 
+-	WARN_ON_ONCE(iocb->ki_flags & IOCB_HAS_METADATA);
+ 	if (nr_pages <= DIO_INLINE_BIO_VECS)
+ 		vecs = inline_vecs;
+ 	else {
+@@ -131,7 +131,7 @@ static void blkdev_bio_end_io(struct bio *bio)
+ 	if (bio->bi_status && !dio->bio.bi_status)
+ 		dio->bio.bi_status = bio->bi_status;
+ 
+-	if (!is_sync && (dio->iocb->ki_flags & IOCB_HAS_METADATA))
++	if (bio_integrity(bio))
+ 		bio_integrity_unmap_user(bio);
+ 
+ 	if (atomic_dec_and_test(&dio->ref)) {
+@@ -233,7 +233,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
+ 			}
+ 			bio->bi_opf |= REQ_NOWAIT;
+ 		}
+-		if (!is_sync && (iocb->ki_flags & IOCB_HAS_METADATA)) {
++		if (iocb->ki_flags & IOCB_HAS_METADATA) {
+ 			ret = bio_integrity_map_iter(bio, iocb->private);
+ 			if (unlikely(ret))
+ 				goto fail;
+@@ -301,7 +301,7 @@ static void blkdev_bio_end_io_async(struct bio *bio)
+ 		ret = blk_status_to_errno(bio->bi_status);
+ 	}
+ 
+-	if (iocb->ki_flags & IOCB_HAS_METADATA)
++	if (bio_integrity(bio))
+ 		bio_integrity_unmap_user(bio);
+ 
+ 	iocb->ki_complete(iocb, ret);
+@@ -422,7 +422,8 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
+ 	}
+ 
+ 	nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1);
+-	if (likely(nr_pages <= BIO_MAX_VECS)) {
++	if (likely(nr_pages <= BIO_MAX_VECS &&
++		   !(iocb->ki_flags & IOCB_HAS_METADATA))) {
+ 		if (is_sync_kiocb(iocb))
+ 			return __blkdev_direct_IO_simple(iocb, iter, bdev,
+ 							nr_pages);
+@@ -672,6 +673,8 @@ static int blkdev_open(struct inode *inode, struct file *filp)
+ 
+ 	if (bdev_can_atomic_write(bdev))
+ 		filp->f_mode |= FMODE_CAN_ATOMIC_WRITE;
++	if (blk_get_integrity(bdev->bd_disk))
++		filp->f_mode |= FMODE_HAS_METADATA;
+ 
+ 	ret = bdev_open(bdev, mode, filp->private_data, NULL, filp);
+ 	if (ret)
+diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
+index f3477ab377425f..e9aaf72502e51a 100644
+--- a/drivers/cpufreq/amd-pstate.c
++++ b/drivers/cpufreq/amd-pstate.c
+@@ -1547,13 +1547,15 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
+ 	pr_debug("CPU %d exiting\n", policy->cpu);
+ }
+ 
+-static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
++static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy, bool policy_change)
+ {
+ 	struct amd_cpudata *cpudata = policy->driver_data;
+ 	union perf_cached perf;
+ 	u8 epp;
+ 
+-	if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq)
++	if (policy_change ||
++	    policy->min != cpudata->min_limit_freq ||
++	    policy->max != cpudata->max_limit_freq)
+ 		amd_pstate_update_min_max_limit(policy);
+ 
+ 	if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
+@@ -1577,7 +1579,7 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
+ 
+ 	cpudata->policy = policy->policy;
+ 
+-	ret = amd_pstate_epp_update_limit(policy);
++	ret = amd_pstate_epp_update_limit(policy, true);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -1619,13 +1621,14 @@ static int amd_pstate_suspend(struct cpufreq_policy *policy)
+ 	 * min_perf value across kexec reboots. If this CPU is just resumed back without kexec,
+ 	 * the limits, epp and desired perf will get reset to the cached values in cpudata struct
+ 	 */
+-	ret = amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
++	ret = amd_pstate_update_perf(policy, perf.bios_min_perf,
++				     FIELD_GET(AMD_CPPC_DES_PERF_MASK, cpudata->cppc_req_cached),
++				     FIELD_GET(AMD_CPPC_MAX_PERF_MASK, cpudata->cppc_req_cached),
++				     FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached),
++				     false);
+ 	if (ret)
+ 		return ret;
+ 
+-	/* invalidate to ensure it's rewritten during resume */
+-	cpudata->cppc_req_cached = 0;
+-
+ 	/* set this flag to avoid setting core offline*/
+ 	cpudata->suspended = true;
+ 
+@@ -1651,7 +1654,7 @@ static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
+ 		int ret;
+ 
+ 		/* enable amd pstate from suspend state*/
+-		ret = amd_pstate_epp_update_limit(policy);
++		ret = amd_pstate_epp_update_limit(policy, false);
+ 		if (ret)
+ 			return ret;
+ 
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index 06a1c7dd081ffb..9a85c58922a0c8 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -1034,8 +1034,8 @@ static bool hybrid_register_perf_domain(unsigned int cpu)
+ 	if (!cpu_dev)
+ 		return false;
+ 
+-	if (em_dev_register_perf_domain(cpu_dev, HYBRID_EM_STATE_COUNT, &cb,
+-					cpumask_of(cpu), false))
++	if (em_dev_register_pd_no_update(cpu_dev, HYBRID_EM_STATE_COUNT, &cb,
++					 cpumask_of(cpu), false))
+ 		return false;
+ 
+ 	cpudata->pd_registered = true;
+diff --git a/drivers/dma/dw/rzn1-dmamux.c b/drivers/dma/dw/rzn1-dmamux.c
+index 4fb8508419dbd8..deadf135681b67 100644
+--- a/drivers/dma/dw/rzn1-dmamux.c
++++ b/drivers/dma/dw/rzn1-dmamux.c
+@@ -48,12 +48,16 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec,
+ 	u32 mask;
+ 	int ret;
+ 
+-	if (dma_spec->args_count != RNZ1_DMAMUX_NCELLS)
+-		return ERR_PTR(-EINVAL);
++	if (dma_spec->args_count != RNZ1_DMAMUX_NCELLS) {
++		ret = -EINVAL;
++		goto put_device;
++	}
+ 
+ 	map = kzalloc(sizeof(*map), GFP_KERNEL);
+-	if (!map)
+-		return ERR_PTR(-ENOMEM);
++	if (!map) {
++		ret = -ENOMEM;
++		goto put_device;
++	}
+ 
+ 	chan = dma_spec->args[0];
+ 	map->req_idx = dma_spec->args[4];
+@@ -94,12 +98,15 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec,
+ 	if (ret)
+ 		goto clear_bitmap;
+ 
++	put_device(&pdev->dev);
+ 	return map;
+ 
+ clear_bitmap:
+ 	clear_bit(map->req_idx, dmamux->used_chans);
+ free_map:
+ 	kfree(map);
++put_device:
++	put_device(&pdev->dev);
+ 
+ 	return ERR_PTR(ret);
+ }
+diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
+index 80355d03004dbd..b559b0e18809e4 100644
+--- a/drivers/dma/idxd/init.c
++++ b/drivers/dma/idxd/init.c
+@@ -189,27 +189,30 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
+ 	idxd->wq_enable_map = bitmap_zalloc_node(idxd->max_wqs, GFP_KERNEL, dev_to_node(dev));
+ 	if (!idxd->wq_enable_map) {
+ 		rc = -ENOMEM;
+-		goto err_bitmap;
++		goto err_free_wqs;
+ 	}
+ 
+ 	for (i = 0; i < idxd->max_wqs; i++) {
+ 		wq = kzalloc_node(sizeof(*wq), GFP_KERNEL, dev_to_node(dev));
+ 		if (!wq) {
+ 			rc = -ENOMEM;
+-			goto err;
++			goto err_unwind;
+ 		}
+ 
+ 		idxd_dev_set_type(&wq->idxd_dev, IDXD_DEV_WQ);
+ 		conf_dev = wq_confdev(wq);
+ 		wq->id = i;
+ 		wq->idxd = idxd;
+-		device_initialize(wq_confdev(wq));
++		device_initialize(conf_dev);
+ 		conf_dev->parent = idxd_confdev(idxd);
+ 		conf_dev->bus = &dsa_bus_type;
+ 		conf_dev->type = &idxd_wq_device_type;
+ 		rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id);
+-		if (rc < 0)
+-			goto err;
++		if (rc < 0) {
++			put_device(conf_dev);
++			kfree(wq);
++			goto err_unwind;
++		}
+ 
+ 		mutex_init(&wq->wq_lock);
+ 		init_waitqueue_head(&wq->err_queue);
+@@ -220,15 +223,20 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
+ 		wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES;
+ 		wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev));
+ 		if (!wq->wqcfg) {
++			put_device(conf_dev);
++			kfree(wq);
+ 			rc = -ENOMEM;
+-			goto err;
++			goto err_unwind;
+ 		}
+ 
+ 		if (idxd->hw.wq_cap.op_config) {
+ 			wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL);
+ 			if (!wq->opcap_bmap) {
++				kfree(wq->wqcfg);
++				put_device(conf_dev);
++				kfree(wq);
+ 				rc = -ENOMEM;
+-				goto err_opcap_bmap;
++				goto err_unwind;
+ 			}
+ 			bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS);
+ 		}
+@@ -239,13 +247,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
+ 
+ 	return 0;
+ 
+-err_opcap_bmap:
+-	kfree(wq->wqcfg);
+-
+-err:
+-	put_device(conf_dev);
+-	kfree(wq);
+-
++err_unwind:
+ 	while (--i >= 0) {
+ 		wq = idxd->wqs[i];
+ 		if (idxd->hw.wq_cap.op_config)
+@@ -254,11 +256,10 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
+ 		conf_dev = wq_confdev(wq);
+ 		put_device(conf_dev);
+ 		kfree(wq);
+-
+ 	}
+ 	bitmap_free(idxd->wq_enable_map);
+ 
+-err_bitmap:
++err_free_wqs:
+ 	kfree(idxd->wqs);
+ 
+ 	return rc;
+@@ -1292,10 +1293,12 @@ static void idxd_remove(struct pci_dev *pdev)
+ 	device_unregister(idxd_confdev(idxd));
+ 	idxd_shutdown(pdev);
+ 	idxd_device_remove_debugfs(idxd);
+-	idxd_cleanup(idxd);
++	perfmon_pmu_remove(idxd);
++	idxd_cleanup_interrupts(idxd);
++	if (device_pasid_enabled(idxd))
++		idxd_disable_system_pasid(idxd);
+ 	pci_iounmap(pdev, idxd->reg_base);
+ 	put_device(idxd_confdev(idxd));
+-	idxd_free(idxd);
+ 	pci_disable_device(pdev);
+ }
+ 
+diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
+index bbc3276992bb01..2cf060174795fe 100644
+--- a/drivers/dma/qcom/bam_dma.c
++++ b/drivers/dma/qcom/bam_dma.c
+@@ -1283,13 +1283,17 @@ static int bam_dma_probe(struct platform_device *pdev)
+ 	if (!bdev->bamclk) {
+ 		ret = of_property_read_u32(pdev->dev.of_node, "num-channels",
+ 					   &bdev->num_channels);
+-		if (ret)
++		if (ret) {
+ 			dev_err(bdev->dev, "num-channels unspecified in dt\n");
++			return ret;
++		}
+ 
+ 		ret = of_property_read_u32(pdev->dev.of_node, "qcom,num-ees",
+ 					   &bdev->num_ees);
+-		if (ret)
++		if (ret) {
+ 			dev_err(bdev->dev, "num-ees unspecified in dt\n");
++			return ret;
++		}
+ 	}
+ 
+ 	ret = clk_prepare_enable(bdev->bamclk);
+diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c
+index 3ed406f08c442e..552be71db6c47b 100644
+--- a/drivers/dma/ti/edma.c
++++ b/drivers/dma/ti/edma.c
+@@ -2064,8 +2064,8 @@ static int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata,
+ 	 * priority. So Q0 is the highest priority queue and the last queue has
+ 	 * the lowest priority.
+ 	 */
+-	queue_priority_map = devm_kcalloc(dev, ecc->num_tc + 1, sizeof(s8),
+-					  GFP_KERNEL);
++	queue_priority_map = devm_kcalloc(dev, ecc->num_tc + 1,
++					  sizeof(*queue_priority_map), GFP_KERNEL);
+ 	if (!queue_priority_map)
+ 		return -ENOMEM;
+ 
+diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
+index cae52c654a15c6..7685a8550d4b1f 100644
+--- a/drivers/edac/altera_edac.c
++++ b/drivers/edac/altera_edac.c
+@@ -128,7 +128,6 @@ static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
+ 
+ 	ptemp = dma_alloc_coherent(mci->pdev, 16, &dma_handle, GFP_KERNEL);
+ 	if (!ptemp) {
+-		dma_free_coherent(mci->pdev, 16, ptemp, dma_handle);
+ 		edac_printk(KERN_ERR, EDAC_MC,
+ 			    "Inject: Buffer Allocation error\n");
+ 		return -ENOMEM;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+index f9ceda7861f1b1..cdafce9781ed32 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+@@ -596,10 +596,6 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
+ 		udelay(1);
+ 	}
+ 
+-	dev_err(adev->dev,
+-		"psp reg (0x%x) wait timed out, mask: %x, read: %x exp: %x",
+-		reg_index, mask, val, reg_val);
+-
+ 	return -ETIME;
+ }
+ 
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+index a4a00855d0b238..428adc7f741de3 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
+@@ -51,17 +51,6 @@
+ #define C2PMSG_CMD_SPI_GET_ROM_IMAGE_ADDR_HI 0x10
+ #define C2PMSG_CMD_SPI_GET_FLASH_IMAGE 0x11
+ 
+-/* Command register bit 31 set to indicate readiness */
+-#define MBOX_TOS_READY_FLAG (GFX_FLAG_RESPONSE)
+-#define MBOX_TOS_READY_MASK (GFX_CMD_RESPONSE_MASK | GFX_CMD_STATUS_MASK)
+-
+-/* Values to check for a successful GFX_CMD response wait. Check against
+- * both status bits and response state - helps to detect a command failure
+- * or other unexpected cases like a device drop reading all 0xFFs
+- */
+-#define MBOX_TOS_RESP_FLAG (GFX_FLAG_RESPONSE)
+-#define MBOX_TOS_RESP_MASK (GFX_CMD_RESPONSE_MASK | GFX_CMD_STATUS_MASK)
+-
+ extern const struct attribute_group amdgpu_flash_attr_group;
+ 
+ enum psp_shared_mem_size {
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+index 7c5584742471e9..a0b7ac7486dc55 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
+@@ -389,8 +389,6 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring)
+ 	dma_fence_put(ring->vmid_wait);
+ 	ring->vmid_wait = NULL;
+ 	ring->me = 0;
+-
+-	ring->adev->rings[ring->idx] = NULL;
+ }
+ 
+ /**
+diff --git a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
+index 574880d6700995..2ab6fa4fcf20b6 100644
+--- a/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
++++ b/drivers/gpu/drm/amd/amdgpu/isp_v4_1_1.c
+@@ -29,6 +29,8 @@
+ #include "amdgpu.h"
+ #include "isp_v4_1_1.h"
+ 
++MODULE_FIRMWARE("amdgpu/isp_4_1_1.bin");
++
+ static const unsigned int isp_4_1_1_int_srcid[MAX_ISP411_INT_SRC] = {
+ 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT9,
+ 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT10,
+diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
+index 2c4ebd98927ff3..145186a1e48f6b 100644
+--- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c
+@@ -94,7 +94,7 @@ static int psp_v10_0_ring_create(struct psp_context *psp,
+ 
+ 	/* Wait for response flag (bit 31) in C2PMSG_64 */
+ 	ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			   MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++			   0x80000000, 0x8000FFFF, false);
+ 
+ 	return ret;
+ }
+@@ -115,7 +115,7 @@ static int psp_v10_0_ring_stop(struct psp_context *psp,
+ 
+ 	/* Wait for response flag (bit 31) in C2PMSG_64 */
+ 	ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			   MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++			   0x80000000, 0x80000000, false);
+ 
+ 	return ret;
+ }
+diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+index 1a4a26e6ffd24c..215543575f477c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
+@@ -277,13 +277,11 @@ static int psp_v11_0_ring_stop(struct psp_context *psp,
+ 
+ 	/* Wait for response flag (bit 31) */
+ 	if (amdgpu_sriov_vf(adev))
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x80000000, false);
+ 	else
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 
+ 	return ret;
+ }
+@@ -319,15 +317,13 @@ static int psp_v11_0_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_101 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x8000FFFF, false);
+ 
+ 	} else {
+ 		/* Wait for sOS ready for ring creation */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_READY_FLAG, MBOX_TOS_READY_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 		if (ret) {
+ 			DRM_ERROR("Failed to wait for sOS ready for ring creation\n");
+ 			return ret;
+@@ -351,9 +347,8 @@ static int psp_v11_0_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_64 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x8000FFFF, false);
+ 	}
+ 
+ 	return ret;
+@@ -386,8 +381,7 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp)
+ 
+ 	offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64);
+ 
+-	ret = psp_wait_for(psp, offset, MBOX_TOS_READY_FLAG,
+-			   MBOX_TOS_READY_MASK, false);
++	ret = psp_wait_for(psp, offset, 0x80000000, 0x8000FFFF, false);
+ 
+ 	if (ret) {
+ 		DRM_INFO("psp is not working correctly before mode1 reset!\n");
+@@ -401,8 +395,7 @@ static int psp_v11_0_mode1_reset(struct psp_context *psp)
+ 
+ 	offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33);
+ 
+-	ret = psp_wait_for(psp, offset, MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK,
+-			   false);
++	ret = psp_wait_for(psp, offset, 0x80000000, 0x80000000, false);
+ 
+ 	if (ret) {
+ 		DRM_INFO("psp mode 1 reset failed!\n");
+diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c
+index 338d015c0f2ee2..5697760a819bc7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c
++++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0_8.c
+@@ -41,9 +41,8 @@ static int psp_v11_0_8_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x80000000, false);
+ 	} else {
+ 		/* Write the ring destroy command*/
+ 		WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_64,
+@@ -51,9 +50,8 @@ static int psp_v11_0_8_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 	}
+ 
+ 	return ret;
+@@ -89,15 +87,13 @@ static int psp_v11_0_8_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_101 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x8000FFFF, false);
+ 
+ 	} else {
+ 		/* Wait for sOS ready for ring creation */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_READY_FLAG, MBOX_TOS_READY_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 		if (ret) {
+ 			DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
+ 			return ret;
+@@ -121,9 +117,8 @@ static int psp_v11_0_8_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_64 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x8000FFFF, false);
+ 	}
+ 
+ 	return ret;
+diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
+index d54b3e0fabaf40..80153f8374704a 100644
+--- a/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/psp_v12_0.c
+@@ -163,7 +163,7 @@ static int psp_v12_0_ring_create(struct psp_context *psp,
+ 
+ 	/* Wait for response flag (bit 31) in C2PMSG_64 */
+ 	ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			   MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++			   0x80000000, 0x8000FFFF, false);
+ 
+ 	return ret;
+ }
+@@ -184,13 +184,11 @@ static int psp_v12_0_ring_stop(struct psp_context *psp,
+ 
+ 	/* Wait for response flag (bit 31) */
+ 	if (amdgpu_sriov_vf(adev))
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x80000000, false);
+ 	else
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 
+ 	return ret;
+ }
+@@ -221,8 +219,7 @@ static int psp_v12_0_mode1_reset(struct psp_context *psp)
+ 
+ 	offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_64);
+ 
+-	ret = psp_wait_for(psp, offset, MBOX_TOS_READY_FLAG,
+-			   MBOX_TOS_READY_MASK, false);
++	ret = psp_wait_for(psp, offset, 0x80000000, 0x8000FFFF, false);
+ 
+ 	if (ret) {
+ 		DRM_INFO("psp is not working correctly before mode1 reset!\n");
+@@ -236,8 +233,7 @@ static int psp_v12_0_mode1_reset(struct psp_context *psp)
+ 
+ 	offset = SOC15_REG_OFFSET(MP0, 0, mmMP0_SMN_C2PMSG_33);
+ 
+-	ret = psp_wait_for(psp, offset, MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK,
+-			   false);
++	ret = psp_wait_for(psp, offset, 0x80000000, 0x80000000, false);
+ 
+ 	if (ret) {
+ 		DRM_INFO("psp mode 1 reset failed!\n");
+diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
+index 58b6b64dcd683b..ead616c117057f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
+@@ -384,9 +384,8 @@ static int psp_v13_0_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x80000000, false);
+ 	} else {
+ 		/* Write the ring destroy command*/
+ 		WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_64,
+@@ -394,9 +393,8 @@ static int psp_v13_0_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 	}
+ 
+ 	return ret;
+@@ -432,15 +430,13 @@ static int psp_v13_0_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_101 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x8000FFFF, false);
+ 
+ 	} else {
+ 		/* Wait for sOS ready for ring creation */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_READY_FLAG, MBOX_TOS_READY_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 		if (ret) {
+ 			DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
+ 			return ret;
+@@ -464,9 +460,8 @@ static int psp_v13_0_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_64 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x8000FFFF, false);
+ 	}
+ 
+ 	return ret;
+diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
+index f65af52c1c1939..eaa5512a21dacd 100644
+--- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
++++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0_4.c
+@@ -204,9 +204,8 @@ static int psp_v13_0_4_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x80000000, false);
+ 	} else {
+ 		/* Write the ring destroy command*/
+ 		WREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_64,
+@@ -214,9 +213,8 @@ static int psp_v13_0_4_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 	}
+ 
+ 	return ret;
+@@ -252,15 +250,13 @@ static int psp_v13_0_4_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_101 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_101),
++				   0x80000000, 0x8000FFFF, false);
+ 
+ 	} else {
+ 		/* Wait for sOS ready for ring creation */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_READY_FLAG, MBOX_TOS_READY_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 		if (ret) {
+ 			DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
+ 			return ret;
+@@ -284,9 +280,8 @@ static int psp_v13_0_4_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_64 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_64),
++				   0x80000000, 0x8000FFFF, false);
+ 	}
+ 
+ 	return ret;
+diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v14_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v14_0.c
+index b029f301aaccaf..30d8eecc567481 100644
+--- a/drivers/gpu/drm/amd/amdgpu/psp_v14_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/psp_v14_0.c
+@@ -250,9 +250,8 @@ static int psp_v14_0_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_101),
++				   0x80000000, 0x80000000, false);
+ 	} else {
+ 		/* Write the ring destroy command*/
+ 		WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_64,
+@@ -260,9 +259,8 @@ static int psp_v14_0_ring_stop(struct psp_context *psp,
+ 		/* there might be handshake issue with hardware which needs delay */
+ 		mdelay(20);
+ 		/* Wait for response flag (bit 31) */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 	}
+ 
+ 	return ret;
+@@ -298,15 +296,13 @@ static int psp_v14_0_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_101 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_101),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_101),
++				   0x80000000, 0x8000FFFF, false);
+ 
+ 	} else {
+ 		/* Wait for sOS ready for ring creation */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+-			MBOX_TOS_READY_FLAG, MBOX_TOS_READY_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
++				   0x80000000, 0x80000000, false);
+ 		if (ret) {
+ 			DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
+ 			return ret;
+@@ -330,9 +326,8 @@ static int psp_v14_0_ring_create(struct psp_context *psp,
+ 		mdelay(20);
+ 
+ 		/* Wait for response flag (bit 31) in C2PMSG_64 */
+-		ret = psp_wait_for(
+-			psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+-			MBOX_TOS_RESP_FLAG, MBOX_TOS_RESP_MASK, false);
++		ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
++				   0x80000000, 0x8000FFFF, false);
+ 	}
+ 
+ 	return ret;
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+index 9fb0d53805892d..614e0886556271 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c
+@@ -1875,15 +1875,19 @@ static int vcn_v3_0_limit_sched(struct amdgpu_cs_parser *p,
+ 				struct amdgpu_job *job)
+ {
+ 	struct drm_gpu_scheduler **scheds;
+-
+-	/* The create msg must be in the first IB submitted */
+-	if (atomic_read(&job->base.entity->fence_seq))
+-		return -EINVAL;
++	struct dma_fence *fence;
+ 
+ 	/* if VCN0 is harvested, we can't support AV1 */
+ 	if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0)
+ 		return -EINVAL;
+ 
++	/* wait for all jobs to finish before switching to instance 0 */
++	fence = amdgpu_ctx_get_fence(p->ctx, job->base.entity, ~0ull);
++	if (fence) {
++		dma_fence_wait(fence, false);
++		dma_fence_put(fence);
++	}
++
+ 	scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_DEC]
+ 		[AMDGPU_RING_PRIO_DEFAULT].sched;
+ 	drm_sched_entity_modify_sched(job->base.entity, scheds, 1);
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+index 46c329a1b2f5f0..e77f2df1beb773 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+@@ -1807,15 +1807,19 @@ static int vcn_v4_0_limit_sched(struct amdgpu_cs_parser *p,
+ 				struct amdgpu_job *job)
+ {
+ 	struct drm_gpu_scheduler **scheds;
+-
+-	/* The create msg must be in the first IB submitted */
+-	if (atomic_read(&job->base.entity->fence_seq))
+-		return -EINVAL;
++	struct dma_fence *fence;
+ 
+ 	/* if VCN0 is harvested, we can't support AV1 */
+ 	if (p->adev->vcn.harvest_config & AMDGPU_VCN_HARVEST_VCN0)
+ 		return -EINVAL;
+ 
++	/* wait for all jobs to finish before switching to instance 0 */
++	fence = amdgpu_ctx_get_fence(p->ctx, job->base.entity, ~0ull);
++	if (fence) {
++		dma_fence_wait(fence, false);
++		dma_fence_put(fence);
++	}
++
+ 	scheds = p->adev->gpu_sched[AMDGPU_HW_IP_VCN_ENC]
+ 		[AMDGPU_RING_PRIO_0].sched;
+ 	drm_sched_entity_modify_sched(job->base.entity, scheds, 1);
+@@ -1906,22 +1910,16 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
+ 
+ #define RADEON_VCN_ENGINE_TYPE_ENCODE			(0x00000002)
+ #define RADEON_VCN_ENGINE_TYPE_DECODE			(0x00000003)
+-
+ #define RADEON_VCN_ENGINE_INFO				(0x30000001)
+-#define RADEON_VCN_ENGINE_INFO_MAX_OFFSET		16
+-
+ #define RENCODE_ENCODE_STANDARD_AV1			2
+ #define RENCODE_IB_PARAM_SESSION_INIT			0x00000003
+-#define RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET	64
+ 
+-/* return the offset in ib if id is found, -1 otherwise
+- * to speed up the searching we only search upto max_offset
+- */
+-static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int max_offset)
++/* return the offset in ib if id is found, -1 otherwise */
++static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start)
+ {
+ 	int i;
+ 
+-	for (i = 0; i < ib->length_dw && i < max_offset && ib->ptr[i] >= 8; i += ib->ptr[i]/4) {
++	for (i = start; i < ib->length_dw && ib->ptr[i] >= 8; i += ib->ptr[i] / 4) {
+ 		if (ib->ptr[i + 1] == id)
+ 			return i;
+ 	}
+@@ -1936,33 +1934,29 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
+ 	struct amdgpu_vcn_decode_buffer *decode_buffer;
+ 	uint64_t addr;
+ 	uint32_t val;
+-	int idx;
++	int idx = 0, sidx;
+ 
+ 	/* The first instance can decode anything */
+ 	if (!ring->me)
+ 		return 0;
+ 
+-	/* RADEON_VCN_ENGINE_INFO is at the top of ib block */
+-	idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO,
+-			RADEON_VCN_ENGINE_INFO_MAX_OFFSET);
+-	if (idx < 0) /* engine info is missing */
+-		return 0;
+-
+-	val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
+-	if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
+-		decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6];
+-
+-		if (!(decode_buffer->valid_buf_flag  & 0x1))
+-			return 0;
+-
+-		addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
+-			decode_buffer->msg_buffer_address_lo;
+-		return vcn_v4_0_dec_msg(p, job, addr);
+-	} else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
+-		idx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT,
+-			RENCODE_IB_PARAM_SESSION_INIT_MAX_OFFSET);
+-		if (idx >= 0 && ib->ptr[idx + 2] == RENCODE_ENCODE_STANDARD_AV1)
+-			return vcn_v4_0_limit_sched(p, job);
++	while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) {
++		val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
++		if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
++			decode_buffer = (struct amdgpu_vcn_decode_buffer *)&ib->ptr[idx + 6];
++
++			if (!(decode_buffer->valid_buf_flag & 0x1))
++				return 0;
++
++			addr = ((u64)decode_buffer->msg_buffer_address_hi) << 32 |
++				decode_buffer->msg_buffer_address_lo;
++			return vcn_v4_0_dec_msg(p, job, addr);
++		} else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
++			sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx);
++			if (sidx >= 0 && ib->ptr[sidx + 2] == RENCODE_ENCODE_STANDARD_AV1)
++				return vcn_v4_0_limit_sched(p, job);
++		}
++		idx += ib->ptr[idx] / 4;
+ 	}
+ 	return 0;
+ }
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 2d94fec5b545d7..312f6075e39d11 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -2910,6 +2910,17 @@ static int dm_oem_i2c_hw_init(struct amdgpu_device *adev)
+ 	return 0;
+ }
+ 
++static void dm_oem_i2c_hw_fini(struct amdgpu_device *adev)
++{
++	struct amdgpu_display_manager *dm = &adev->dm;
++
++	if (dm->oem_i2c) {
++		i2c_del_adapter(&dm->oem_i2c->base);
++		kfree(dm->oem_i2c);
++		dm->oem_i2c = NULL;
++	}
++}
++
+ /**
+  * dm_hw_init() - Initialize DC device
+  * @ip_block: Pointer to the amdgpu_ip_block for this hw instance.
+@@ -2960,7 +2971,7 @@ static int dm_hw_fini(struct amdgpu_ip_block *ip_block)
+ {
+ 	struct amdgpu_device *adev = ip_block->adev;
+ 
+-	kfree(adev->dm.oem_i2c);
++	dm_oem_i2c_hw_fini(adev);
+ 
+ 	amdgpu_dm_hpd_fini(adev);
+ 
+@@ -3073,16 +3084,55 @@ static int dm_cache_state(struct amdgpu_device *adev)
+ 	return adev->dm.cached_state ? 0 : r;
+ }
+ 
+-static int dm_prepare_suspend(struct amdgpu_ip_block *ip_block)
++static void dm_destroy_cached_state(struct amdgpu_device *adev)
+ {
+-	struct amdgpu_device *adev = ip_block->adev;
++	struct amdgpu_display_manager *dm = &adev->dm;
++	struct drm_device *ddev = adev_to_drm(adev);
++	struct dm_plane_state *dm_new_plane_state;
++	struct drm_plane_state *new_plane_state;
++	struct dm_crtc_state *dm_new_crtc_state;
++	struct drm_crtc_state *new_crtc_state;
++	struct drm_plane *plane;
++	struct drm_crtc *crtc;
++	int i;
+ 
+-	if (amdgpu_in_reset(adev))
+-		return 0;
++	if (!dm->cached_state)
++		return;
++
++	/* Force mode set in atomic commit */
++	for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) {
++		new_crtc_state->active_changed = true;
++		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
++		reset_freesync_config_for_crtc(dm_new_crtc_state);
++	}
++
++	/*
++	 * atomic_check is expected to create the dc states. We need to release
++	 * them here, since they were duplicated as part of the suspend
++	 * procedure.
++	 */
++	for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) {
++		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
++		if (dm_new_crtc_state->stream) {
++			WARN_ON(kref_read(&dm_new_crtc_state->stream->refcount) > 1);
++			dc_stream_release(dm_new_crtc_state->stream);
++			dm_new_crtc_state->stream = NULL;
++		}
++		dm_new_crtc_state->base.color_mgmt_changed = true;
++	}
++
++	for_each_new_plane_in_state(dm->cached_state, plane, new_plane_state, i) {
++		dm_new_plane_state = to_dm_plane_state(new_plane_state);
++		if (dm_new_plane_state->dc_state) {
++			WARN_ON(kref_read(&dm_new_plane_state->dc_state->refcount) > 1);
++			dc_plane_state_release(dm_new_plane_state->dc_state);
++			dm_new_plane_state->dc_state = NULL;
++		}
++	}
+ 
+-	WARN_ON(adev->dm.cached_state);
++	drm_atomic_helper_resume(ddev, dm->cached_state);
+ 
+-	return dm_cache_state(adev);
++	dm->cached_state = NULL;
+ }
+ 
+ static int dm_suspend(struct amdgpu_ip_block *ip_block)
+@@ -3306,12 +3356,6 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
+ 	struct amdgpu_dm_connector *aconnector;
+ 	struct drm_connector *connector;
+ 	struct drm_connector_list_iter iter;
+-	struct drm_crtc *crtc;
+-	struct drm_crtc_state *new_crtc_state;
+-	struct dm_crtc_state *dm_new_crtc_state;
+-	struct drm_plane *plane;
+-	struct drm_plane_state *new_plane_state;
+-	struct dm_plane_state *dm_new_plane_state;
+ 	struct dm_atomic_state *dm_state = to_dm_atomic_state(dm->atomic_obj.state);
+ 	enum dc_connection_type new_connection_type = dc_connection_none;
+ 	struct dc_state *dc_state;
+@@ -3470,40 +3514,7 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
+ 	}
+ 	drm_connector_list_iter_end(&iter);
+ 
+-	/* Force mode set in atomic commit */
+-	for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) {
+-		new_crtc_state->active_changed = true;
+-		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+-		reset_freesync_config_for_crtc(dm_new_crtc_state);
+-	}
+-
+-	/*
+-	 * atomic_check is expected to create the dc states. We need to release
+-	 * them here, since they were duplicated as part of the suspend
+-	 * procedure.
+-	 */
+-	for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) {
+-		dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+-		if (dm_new_crtc_state->stream) {
+-			WARN_ON(kref_read(&dm_new_crtc_state->stream->refcount) > 1);
+-			dc_stream_release(dm_new_crtc_state->stream);
+-			dm_new_crtc_state->stream = NULL;
+-		}
+-		dm_new_crtc_state->base.color_mgmt_changed = true;
+-	}
+-
+-	for_each_new_plane_in_state(dm->cached_state, plane, new_plane_state, i) {
+-		dm_new_plane_state = to_dm_plane_state(new_plane_state);
+-		if (dm_new_plane_state->dc_state) {
+-			WARN_ON(kref_read(&dm_new_plane_state->dc_state->refcount) > 1);
+-			dc_plane_state_release(dm_new_plane_state->dc_state);
+-			dm_new_plane_state->dc_state = NULL;
+-		}
+-	}
+-
+-	drm_atomic_helper_resume(ddev, dm->cached_state);
+-
+-	dm->cached_state = NULL;
++	dm_destroy_cached_state(adev);
+ 
+ 	/* Do mst topology probing after resuming cached state*/
+ 	drm_connector_list_iter_begin(ddev, &iter);
+@@ -3549,7 +3560,6 @@ static const struct amd_ip_funcs amdgpu_dm_funcs = {
+ 	.early_fini = amdgpu_dm_early_fini,
+ 	.hw_init = dm_hw_init,
+ 	.hw_fini = dm_hw_fini,
+-	.prepare_suspend = dm_prepare_suspend,
+ 	.suspend = dm_suspend,
+ 	.resume = dm_resume,
+ 	.is_idle = dm_is_idle,
+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 25e8befbcc479a..99fd064324baa6 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
+@@ -809,6 +809,7 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
+ 	drm_dp_aux_init(&aconnector->dm_dp_aux.aux);
+ 	drm_dp_cec_register_connector(&aconnector->dm_dp_aux.aux,
+ 				      &aconnector->base);
++	drm_dp_dpcd_set_probe(&aconnector->dm_dp_aux.aux, false);
+ 
+ 	if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_eDP)
+ 		return;
+diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
+index f41073c0147e23..7dfbfb18593c12 100644
+--- a/drivers/gpu/drm/amd/display/dc/dc.h
++++ b/drivers/gpu/drm/amd/display/dc/dc.h
+@@ -1095,6 +1095,7 @@ struct dc_debug_options {
+ 	bool enable_hblank_borrow;
+ 	bool force_subvp_df_throttle;
+ 	uint32_t acpi_transition_bitmasks[MAX_PIPES];
++	bool enable_pg_cntl_debug_logs;
+ };
+ 
+ 
+diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
+index 58c84f555c0fb8..0ce9489ac6b728 100644
+--- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
++++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
+@@ -133,30 +133,34 @@ enum dsc_clk_source {
+ };
+ 
+ 
+-static void dccg35_set_dsc_clk_rcg(struct dccg *dccg, int inst, bool enable)
++static void dccg35_set_dsc_clk_rcg(struct dccg *dccg, int inst, bool allow_rcg)
+ {
+ 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+ 
+-	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc && enable)
++	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc && allow_rcg)
+ 		return;
+ 
+ 	switch (inst) {
+ 	case 0:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	case 1:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	case 2:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	case 3:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	default:
+ 		BREAK_TO_DEBUGGER();
+ 		return;
+ 	}
++
++	/* Wait for clock to ramp */
++	if (!allow_rcg)
++		udelay(10);
+ }
+ 
+ static void dccg35_set_symclk32_se_rcg(
+@@ -385,35 +389,34 @@ static void dccg35_set_dtbclk_p_rcg(struct dccg *dccg, int inst, bool enable)
+ 	}
+ }
+ 
+-static void dccg35_set_dppclk_rcg(struct dccg *dccg,
+-												int inst, bool enable)
++static void dccg35_set_dppclk_rcg(struct dccg *dccg, int inst, bool allow_rcg)
+ {
+-
+ 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+ 
+-
+-	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && enable)
++	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && allow_rcg)
+ 		return;
+ 
+ 	switch (inst) {
+ 	case 0:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	case 1:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	case 2:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	case 3:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, enable ? 0 : 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
+ 		break;
+ 	default:
+ 	BREAK_TO_DEBUGGER();
+ 		break;
+ 	}
+-	//DC_LOG_DEBUG("%s: inst(%d) DPPCLK rcg_disable: %d\n", __func__, inst, enable ? 0 : 1);
+ 
++	/* Wait for clock to ramp */
++	if (!allow_rcg)
++		udelay(10);
+ }
+ 
+ static void dccg35_set_dpstreamclk_rcg(
+@@ -1177,32 +1180,34 @@ static void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst,
+ }
+ 
+ static void dccg35_set_dppclk_root_clock_gating(struct dccg *dccg,
+-		 uint32_t dpp_inst, uint32_t enable)
++		 uint32_t dpp_inst, uint32_t disallow_rcg)
+ {
+ 	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+ 
+-	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp)
++	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && !disallow_rcg)
+ 		return;
+ 
+ 
+ 	switch (dpp_inst) {
+ 	case 0:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, disallow_rcg);
+ 		break;
+ 	case 1:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, enable);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, disallow_rcg);
+ 		break;
+ 	case 2:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, enable);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, disallow_rcg);
+ 		break;
+ 	case 3:
+-		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, enable);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, disallow_rcg);
+ 		break;
+ 	default:
+ 		break;
+ 	}
+-	//DC_LOG_DEBUG("%s: dpp_inst(%d) rcg: %d\n", __func__, dpp_inst, enable);
+ 
++	/* Wait for clock to ramp */
++	if (disallow_rcg)
++		udelay(10);
+ }
+ 
+ static void dccg35_get_pixel_rate_div(
+@@ -1782,8 +1787,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
+ 	//Disable DTO
+ 	switch (inst) {
+ 	case 0:
+-		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
+-			REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, 1);
+ 
+ 		REG_UPDATE_2(DSCCLK0_DTO_PARAM,
+ 				DSCCLK0_DTO_PHASE, 0,
+@@ -1791,8 +1795,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
+ 		REG_UPDATE(DSCCLK_DTO_CTRL,	DSCCLK0_EN, 1);
+ 		break;
+ 	case 1:
+-		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
+-			REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, 1);
+ 
+ 		REG_UPDATE_2(DSCCLK1_DTO_PARAM,
+ 				DSCCLK1_DTO_PHASE, 0,
+@@ -1800,8 +1803,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
+ 		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
+ 		break;
+ 	case 2:
+-		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
+-			REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, 1);
+ 
+ 		REG_UPDATE_2(DSCCLK2_DTO_PARAM,
+ 				DSCCLK2_DTO_PHASE, 0,
+@@ -1809,8 +1811,7 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
+ 		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
+ 		break;
+ 	case 3:
+-		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
+-			REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, 1);
++		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, 1);
+ 
+ 		REG_UPDATE_2(DSCCLK3_DTO_PARAM,
+ 				DSCCLK3_DTO_PHASE, 0,
+@@ -1821,6 +1822,9 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
+ 		BREAK_TO_DEBUGGER();
+ 		return;
+ 	}
++
++	/* Wait for clock to ramp */
++	udelay(10);
+ }
+ 
+ static void dccg35_disable_dscclk(struct dccg *dccg,
+@@ -1864,6 +1868,9 @@ static void dccg35_disable_dscclk(struct dccg *dccg,
+ 	default:
+ 		return;
+ 	}
++
++	/* Wait for clock ramp */
++	udelay(10);
+ }
+ 
+ static void dccg35_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)
+@@ -2349,10 +2356,7 @@ static void dccg35_disable_symclk_se_cb(
+ 
+ void dccg35_root_gate_disable_control(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating)
+ {
+-
+-	if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) {
+-		dccg35_set_dppclk_root_clock_gating(dccg, pipe_idx, disable_clock_gating);
+-	}
++	dccg35_set_dppclk_root_clock_gating(dccg, pipe_idx, disable_clock_gating);
+ }
+ 
+ static const struct dccg_funcs dccg35_funcs_new = {
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+index cdb8685ae7d719..454e362ff096aa 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
+@@ -955,7 +955,7 @@ enum dc_status dcn20_enable_stream_timing(
+ 		return DC_ERROR_UNEXPECTED;
+ 	}
+ 
+-	fsleep(stream->timing.v_total * (stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz));
++	udelay(stream->timing.v_total * (stream->timing.h_total * 10000u / stream->timing.pix_clk_100hz));
+ 
+ 	params.vertical_total_min = stream->adjust.v_total_min;
+ 	params.vertical_total_max = stream->adjust.v_total_max;
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+index a267f574b61937..764eff6a4ec6b7 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
+@@ -113,6 +113,14 @@ static void enable_memory_low_power(struct dc *dc)
+ }
+ #endif
+ 
++static void print_pg_status(struct dc *dc, const char *debug_func, const char *debug_log)
++{
++	if (dc->debug.enable_pg_cntl_debug_logs && dc->res_pool->pg_cntl) {
++		if (dc->res_pool->pg_cntl->funcs->print_pg_status)
++			dc->res_pool->pg_cntl->funcs->print_pg_status(dc->res_pool->pg_cntl, debug_func, debug_log);
++	}
++}
++
+ void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable)
+ {
+ 	REG_UPDATE_3(DMU_CLK_CNTL,
+@@ -137,6 +145,8 @@ void dcn35_init_hw(struct dc *dc)
+ 	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
+ 	int i;
+ 
++	print_pg_status(dc, __func__, ": start");
++
+ 	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
+ 		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
+ 
+@@ -200,10 +210,7 @@ void dcn35_init_hw(struct dc *dc)
+ 
+ 	/* we want to turn off all dp displays before doing detection */
+ 	dc->link_srv->blank_all_dp_displays(dc);
+-/*
+-	if (hws->funcs.enable_power_gating_plane)
+-		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
+-*/
++
+ 	if (res_pool->hubbub && res_pool->hubbub->funcs->dchubbub_init)
+ 		res_pool->hubbub->funcs->dchubbub_init(dc->res_pool->hubbub);
+ 	/* If taking control over from VBIOS, we may want to optimize our first
+@@ -236,6 +243,8 @@ void dcn35_init_hw(struct dc *dc)
+ 		}
+ 
+ 		hws->funcs.init_pipes(dc, dc->current_state);
++		print_pg_status(dc, __func__, ": after init_pipes");
++
+ 		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control &&
+ 			!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter)
+ 			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
+@@ -312,6 +321,7 @@ void dcn35_init_hw(struct dc *dc)
+ 		if (dc->res_pool->pg_cntl->funcs->init_pg_status)
+ 			dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl);
+ 	}
++	print_pg_status(dc, __func__, ": after init_pg_status");
+ }
+ 
+ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+@@ -500,97 +510,6 @@ void dcn35_physymclk_root_clock_control(struct dce_hwseq *hws, unsigned int phy_
+ 	}
+ }
+ 
+-void dcn35_dsc_pg_control(
+-		struct dce_hwseq *hws,
+-		unsigned int dsc_inst,
+-		bool power_on)
+-{
+-	uint32_t power_gate = power_on ? 0 : 1;
+-	uint32_t pwr_status = power_on ? 0 : 2;
+-	uint32_t org_ip_request_cntl = 0;
+-
+-	if (hws->ctx->dc->debug.disable_dsc_power_gate)
+-		return;
+-	if (hws->ctx->dc->debug.ignore_pg)
+-		return;
+-	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
+-	if (org_ip_request_cntl == 0)
+-		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
+-
+-	switch (dsc_inst) {
+-	case 0: /* DSC0 */
+-		REG_UPDATE(DOMAIN16_PG_CONFIG,
+-				DOMAIN_POWER_GATE, power_gate);
+-
+-		REG_WAIT(DOMAIN16_PG_STATUS,
+-				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
+-		break;
+-	case 1: /* DSC1 */
+-		REG_UPDATE(DOMAIN17_PG_CONFIG,
+-				DOMAIN_POWER_GATE, power_gate);
+-
+-		REG_WAIT(DOMAIN17_PG_STATUS,
+-				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
+-		break;
+-	case 2: /* DSC2 */
+-		REG_UPDATE(DOMAIN18_PG_CONFIG,
+-				DOMAIN_POWER_GATE, power_gate);
+-
+-		REG_WAIT(DOMAIN18_PG_STATUS,
+-				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
+-		break;
+-	case 3: /* DSC3 */
+-		REG_UPDATE(DOMAIN19_PG_CONFIG,
+-				DOMAIN_POWER_GATE, power_gate);
+-
+-		REG_WAIT(DOMAIN19_PG_STATUS,
+-				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
+-		break;
+-	default:
+-		BREAK_TO_DEBUGGER();
+-		break;
+-	}
+-
+-	if (org_ip_request_cntl == 0)
+-		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
+-}
+-
+-void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable)
+-{
+-	bool force_on = true; /* disable power gating */
+-	uint32_t org_ip_request_cntl = 0;
+-
+-	if (hws->ctx->dc->debug.disable_hubp_power_gate)
+-		return;
+-	if (hws->ctx->dc->debug.ignore_pg)
+-		return;
+-	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
+-	if (org_ip_request_cntl == 0)
+-		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
+-	/* DCHUBP0/1/2/3/4/5 */
+-	REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-	REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-	/* DPP0/1/2/3/4/5 */
+-	REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-	REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-
+-	force_on = true; /* disable power gating */
+-	if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate)
+-		force_on = false;
+-
+-	/* DCS0/1/2/3/4 */
+-	REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-	REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-	REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-	REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+-
+-
+-}
+-
+ /* In headless boot cases, DIG may be turned
+  * on which causes HW/SW discrepancies.
+  * To avoid this, power down hardware on boot
+@@ -1453,6 +1372,8 @@ void dcn35_prepare_bandwidth(
+ 	}
+ 
+ 	dcn20_prepare_bandwidth(dc, context);
++
++	print_pg_status(dc, __func__, ": after rcg and power up");
+ }
+ 
+ void dcn35_optimize_bandwidth(
+@@ -1461,6 +1382,8 @@ void dcn35_optimize_bandwidth(
+ {
+ 	struct pg_block_update pg_update_state;
+ 
++	print_pg_status(dc, __func__, ": before rcg and power up");
++
+ 	dcn20_optimize_bandwidth(dc, context);
+ 
+ 	if (dc->hwss.calc_blocks_to_gate) {
+@@ -1472,6 +1395,8 @@ void dcn35_optimize_bandwidth(
+ 		if (dc->hwss.root_clock_control)
+ 			dc->hwss.root_clock_control(dc, &pg_update_state, false);
+ 	}
++
++	print_pg_status(dc, __func__, ": after rcg and power up");
+ }
+ 
+ void dcn35_set_drr(struct pipe_ctx **pipe_ctx,
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+index a3ccf805bd16ae..aefb7c47374158 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
+@@ -115,7 +115,6 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
+ 	.exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
+ 	.update_visual_confirm_color = dcn10_update_visual_confirm_color,
+ 	.apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations,
+-	.update_dsc_pg = dcn32_update_dsc_pg,
+ 	.calc_blocks_to_gate = dcn35_calc_blocks_to_gate,
+ 	.calc_blocks_to_ungate = dcn35_calc_blocks_to_ungate,
+ 	.hw_block_power_up = dcn35_hw_block_power_up,
+@@ -150,7 +149,6 @@ static const struct hwseq_private_funcs dcn35_private_funcs = {
+ 	.plane_atomic_disable = dcn35_plane_atomic_disable,
+ 	//.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/
+ 	//.hubp_pg_control = dcn35_hubp_pg_control,
+-	.enable_power_gating_plane = dcn35_enable_power_gating_plane,
+ 	.dpp_root_clock_control = dcn35_dpp_root_clock_control,
+ 	.dpstream_root_clock_control = dcn35_dpstream_root_clock_control,
+ 	.physymclk_root_clock_control = dcn35_physymclk_root_clock_control,
+@@ -165,7 +163,6 @@ static const struct hwseq_private_funcs dcn35_private_funcs = {
+ 	.calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values,
+ 	.resync_fifo_dccg_dio = dcn314_resync_fifo_dccg_dio,
+ 	.is_dp_dig_pixel_rate_div_policy = dcn35_is_dp_dig_pixel_rate_div_policy,
+-	.dsc_pg_control = dcn35_dsc_pg_control,
+ 	.dsc_pg_status = dcn32_dsc_pg_status,
+ 	.enable_plane = dcn35_enable_plane,
+ 	.wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
+index 58f2be2a326b89..a580a55695c3b0 100644
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
+@@ -114,7 +114,6 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
+ 	.exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
+ 	.update_visual_confirm_color = dcn10_update_visual_confirm_color,
+ 	.apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations,
+-	.update_dsc_pg = dcn32_update_dsc_pg,
+ 	.calc_blocks_to_gate = dcn351_calc_blocks_to_gate,
+ 	.calc_blocks_to_ungate = dcn351_calc_blocks_to_ungate,
+ 	.hw_block_power_up = dcn351_hw_block_power_up,
+@@ -145,7 +144,6 @@ static const struct hwseq_private_funcs dcn351_private_funcs = {
+ 	.plane_atomic_disable = dcn35_plane_atomic_disable,
+ 	//.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/
+ 	//.hubp_pg_control = dcn35_hubp_pg_control,
+-	.enable_power_gating_plane = dcn35_enable_power_gating_plane,
+ 	.dpp_root_clock_control = dcn35_dpp_root_clock_control,
+ 	.dpstream_root_clock_control = dcn35_dpstream_root_clock_control,
+ 	.physymclk_root_clock_control = dcn35_physymclk_root_clock_control,
+@@ -159,7 +157,6 @@ static const struct hwseq_private_funcs dcn351_private_funcs = {
+ 	.setup_hpo_hw_control = dcn35_setup_hpo_hw_control,
+ 	.calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values,
+ 	.is_dp_dig_pixel_rate_div_policy = dcn35_is_dp_dig_pixel_rate_div_policy,
+-	.dsc_pg_control = dcn35_dsc_pg_control,
+ 	.dsc_pg_status = dcn32_dsc_pg_status,
+ 	.enable_plane = dcn35_enable_plane,
+ 	.wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h
+index 00ea3864dd4df4..bcd0b0dd9c429a 100644
+--- a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h
+@@ -47,6 +47,7 @@ struct pg_cntl_funcs {
+ 	void (*optc_pg_control)(struct pg_cntl *pg_cntl, unsigned int optc_inst, bool power_on);
+ 	void (*dwb_pg_control)(struct pg_cntl *pg_cntl, bool power_on);
+ 	void (*init_pg_status)(struct pg_cntl *pg_cntl);
++	void (*print_pg_status)(struct pg_cntl *pg_cntl, const char *debug_func, const char *debug_log);
+ };
+ 
+ #endif //__DC_PG_CNTL_H__
+diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c
+index af21c0a27f8657..72bd43f9bbe288 100644
+--- a/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c
++++ b/drivers/gpu/drm/amd/display/dc/pg/dcn35/dcn35_pg_cntl.c
+@@ -79,16 +79,12 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo
+ 	uint32_t power_gate = power_on ? 0 : 1;
+ 	uint32_t pwr_status = power_on ? 0 : 2;
+ 	uint32_t org_ip_request_cntl = 0;
+-	bool block_enabled;
+-
+-	/*need to enable dscclk regardless DSC_PG*/
+-	if (pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc && power_on)
+-		pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc(
+-				pg_cntl->ctx->dc->res_pool->dccg, dsc_inst);
++	bool block_enabled = false;
++	bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg ||
++		       pg_cntl->ctx->dc->debug.disable_dsc_power_gate ||
++		       pg_cntl->ctx->dc->idle_optimizations_allowed;
+ 
+-	if (pg_cntl->ctx->dc->debug.ignore_pg ||
+-		pg_cntl->ctx->dc->debug.disable_dsc_power_gate ||
+-		pg_cntl->ctx->dc->idle_optimizations_allowed)
++	if (skip_pg && !power_on)
+ 		return;
+ 
+ 	block_enabled = pg_cntl35_dsc_pg_status(pg_cntl, dsc_inst);
+@@ -111,7 +107,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo
+ 
+ 		REG_WAIT(DOMAIN16_PG_STATUS,
+ 				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
++				1, 10000);
+ 		break;
+ 	case 1: /* DSC1 */
+ 		REG_UPDATE(DOMAIN17_PG_CONFIG,
+@@ -119,7 +115,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo
+ 
+ 		REG_WAIT(DOMAIN17_PG_STATUS,
+ 				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
++				1, 10000);
+ 		break;
+ 	case 2: /* DSC2 */
+ 		REG_UPDATE(DOMAIN18_PG_CONFIG,
+@@ -127,7 +123,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo
+ 
+ 		REG_WAIT(DOMAIN18_PG_STATUS,
+ 				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
++				1, 10000);
+ 		break;
+ 	case 3: /* DSC3 */
+ 		REG_UPDATE(DOMAIN19_PG_CONFIG,
+@@ -135,7 +131,7 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo
+ 
+ 		REG_WAIT(DOMAIN19_PG_STATUS,
+ 				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
+-				1, 1000);
++				1, 10000);
+ 		break;
+ 	default:
+ 		BREAK_TO_DEBUGGER();
+@@ -144,12 +140,6 @@ void pg_cntl35_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo
+ 
+ 	if (dsc_inst < MAX_PIPES)
+ 		pg_cntl->pg_pipe_res_enable[PG_DSC][dsc_inst] = power_on;
+-
+-	if (pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) {
+-		/*this is to disable dscclk*/
+-		pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc(
+-			pg_cntl->ctx->dc->res_pool->dccg, dsc_inst);
+-	}
+ }
+ 
+ static bool pg_cntl35_hubp_dpp_pg_status(struct pg_cntl *pg_cntl, unsigned int hubp_dpp_inst)
+@@ -189,11 +179,12 @@ void pg_cntl35_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp
+ 	uint32_t pwr_status = power_on ? 0 : 2;
+ 	uint32_t org_ip_request_cntl;
+ 	bool block_enabled;
++	bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg ||
++		       pg_cntl->ctx->dc->debug.disable_hubp_power_gate ||
++		       pg_cntl->ctx->dc->debug.disable_dpp_power_gate ||
++		       pg_cntl->ctx->dc->idle_optimizations_allowed;
+ 
+-	if (pg_cntl->ctx->dc->debug.ignore_pg ||
+-		pg_cntl->ctx->dc->debug.disable_hubp_power_gate ||
+-		pg_cntl->ctx->dc->debug.disable_dpp_power_gate ||
+-		pg_cntl->ctx->dc->idle_optimizations_allowed)
++	if (skip_pg && !power_on)
+ 		return;
+ 
+ 	block_enabled = pg_cntl35_hubp_dpp_pg_status(pg_cntl, hubp_dpp_inst);
+@@ -213,22 +204,22 @@ void pg_cntl35_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp
+ 	case 0:
+ 		/* DPP0 & HUBP0 */
+ 		REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, power_gate);
+-		REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
++		REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000);
+ 		break;
+ 	case 1:
+ 		/* DPP1 & HUBP1 */
+ 		REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, power_gate);
+-		REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
++		REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000);
+ 		break;
+ 	case 2:
+ 		/* DPP2 & HUBP2 */
+ 		REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, power_gate);
+-		REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
++		REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000);
+ 		break;
+ 	case 3:
+ 		/* DPP3 & HUBP3 */
+ 		REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, power_gate);
+-		REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
++		REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 10000);
+ 		break;
+ 	default:
+ 		BREAK_TO_DEBUGGER();
+@@ -501,6 +492,36 @@ void pg_cntl35_init_pg_status(struct pg_cntl *pg_cntl)
+ 	pg_cntl->pg_res_enable[PG_DWB] = block_enabled;
+ }
+ 
++static void pg_cntl35_print_pg_status(struct pg_cntl *pg_cntl, const char *debug_func, const char *debug_log)
++{
++	int i = 0;
++	bool block_enabled = false;
++
++	DC_LOG_DEBUG("%s: %s", debug_func, debug_log);
++
++	DC_LOG_DEBUG("PG_CNTL status:\n");
++
++	block_enabled = pg_cntl35_io_clk_status(pg_cntl);
++	DC_LOG_DEBUG("ONO0=%d (DCCG, DIO, DCIO)\n", block_enabled ? 1 : 0);
++
++	block_enabled = pg_cntl35_mem_status(pg_cntl);
++	DC_LOG_DEBUG("ONO1=%d (DCHUBBUB, DCHVM, DCHUBBUBMEM)\n", block_enabled ? 1 : 0);
++
++	block_enabled = pg_cntl35_plane_otg_status(pg_cntl);
++	DC_LOG_DEBUG("ONO2=%d (MPC, OPP, OPTC, DWB)\n", block_enabled ? 1 : 0);
++
++	block_enabled = pg_cntl35_hpo_pg_status(pg_cntl);
++	DC_LOG_DEBUG("ONO3=%d (HPO)\n", block_enabled ? 1 : 0);
++
++	for (i = 0; i < pg_cntl->ctx->dc->res_pool->pipe_count; i++) {
++		block_enabled = pg_cntl35_hubp_dpp_pg_status(pg_cntl, i);
++		DC_LOG_DEBUG("ONO%d=%d (DCHUBP%d, DPP%d)\n", 4 + i * 2, block_enabled ? 1 : 0, i, i);
++
++		block_enabled = pg_cntl35_dsc_pg_status(pg_cntl, i);
++		DC_LOG_DEBUG("ONO%d=%d (DSC%d)\n", 5 + i * 2, block_enabled ? 1 : 0, i);
++	}
++}
++
+ static const struct pg_cntl_funcs pg_cntl35_funcs = {
+ 	.init_pg_status = pg_cntl35_init_pg_status,
+ 	.dsc_pg_control = pg_cntl35_dsc_pg_control,
+@@ -511,7 +532,8 @@ static const struct pg_cntl_funcs pg_cntl35_funcs = {
+ 	.mpcc_pg_control = pg_cntl35_mpcc_pg_control,
+ 	.opp_pg_control = pg_cntl35_opp_pg_control,
+ 	.optc_pg_control = pg_cntl35_optc_pg_control,
+-	.dwb_pg_control = pg_cntl35_dwb_pg_control
++	.dwb_pg_control = pg_cntl35_dwb_pg_control,
++	.print_pg_status = pg_cntl35_print_pg_status
+ };
+ 
+ struct pg_cntl *pg_cntl35_create(
+diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c
+index ea78c6c8ca7a63..2d4e9368394641 100644
+--- a/drivers/gpu/drm/display/drm_dp_helper.c
++++ b/drivers/gpu/drm/display/drm_dp_helper.c
+@@ -691,6 +691,34 @@ void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered)
+ }
+ EXPORT_SYMBOL(drm_dp_dpcd_set_powered);
+ 
++/**
++ * drm_dp_dpcd_set_probe() - Set whether a probing before DPCD access is done
++ * @aux: DisplayPort AUX channel
++ * @enable: Enable the probing if required
++ */
++void drm_dp_dpcd_set_probe(struct drm_dp_aux *aux, bool enable)
++{
++	WRITE_ONCE(aux->dpcd_probe_disabled, !enable);
++}
++EXPORT_SYMBOL(drm_dp_dpcd_set_probe);
++
++static bool dpcd_access_needs_probe(struct drm_dp_aux *aux)
++{
++	/*
++	 * HP ZR24w corrupts the first DPCD access after entering power save
++	 * mode. Eg. on a read, the entire buffer will be filled with the same
++	 * byte. Do a throw away read to avoid corrupting anything we care
++	 * about. Afterwards things will work correctly until the monitor
++	 * gets woken up and subsequently re-enters power save mode.
++	 *
++	 * The user pressing any button on the monitor is enough to wake it
++	 * up, so there is no particularly good place to do the workaround.
++	 * We just have to do it before any DPCD access and hope that the
++	 * monitor doesn't power down exactly after the throw away read.
++	 */
++	return !aux->is_remote && !READ_ONCE(aux->dpcd_probe_disabled);
++}
++
+ /**
+  * drm_dp_dpcd_read() - read a series of bytes from the DPCD
+  * @aux: DisplayPort AUX channel (SST or MST)
+@@ -712,19 +740,7 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
+ {
+ 	int ret;
+ 
+-	/*
+-	 * HP ZR24w corrupts the first DPCD access after entering power save
+-	 * mode. Eg. on a read, the entire buffer will be filled with the same
+-	 * byte. Do a throw away read to avoid corrupting anything we care
+-	 * about. Afterwards things will work correctly until the monitor
+-	 * gets woken up and subsequently re-enters power save mode.
+-	 *
+-	 * The user pressing any button on the monitor is enough to wake it
+-	 * up, so there is no particularly good place to do the workaround.
+-	 * We just have to do it before any DPCD access and hope that the
+-	 * monitor doesn't power down exactly after the throw away read.
+-	 */
+-	if (!aux->is_remote) {
++	if (dpcd_access_needs_probe(aux)) {
+ 		ret = drm_dp_dpcd_probe(aux, DP_TRAINING_PATTERN_SET);
+ 		if (ret < 0)
+ 			return ret;
+diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
+index 74e77742b2bd4f..9c8822b337e2e4 100644
+--- a/drivers/gpu/drm/drm_edid.c
++++ b/drivers/gpu/drm/drm_edid.c
+@@ -66,34 +66,36 @@ static int oui(u8 first, u8 second, u8 third)
+  * on as many displays as possible).
+  */
+ 
+-/* First detailed mode wrong, use largest 60Hz mode */
+-#define EDID_QUIRK_PREFER_LARGE_60		(1 << 0)
+-/* Reported 135MHz pixel clock is too high, needs adjustment */
+-#define EDID_QUIRK_135_CLOCK_TOO_HIGH		(1 << 1)
+-/* Prefer the largest mode at 75 Hz */
+-#define EDID_QUIRK_PREFER_LARGE_75		(1 << 2)
+-/* Detail timing is in cm not mm */
+-#define EDID_QUIRK_DETAILED_IN_CM		(1 << 3)
+-/* Detailed timing descriptors have bogus size values, so just take the
+- * maximum size and use that.
+- */
+-#define EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE	(1 << 4)
+-/* use +hsync +vsync for detailed mode */
+-#define EDID_QUIRK_DETAILED_SYNC_PP		(1 << 6)
+-/* Force reduced-blanking timings for detailed modes */
+-#define EDID_QUIRK_FORCE_REDUCED_BLANKING	(1 << 7)
+-/* Force 8bpc */
+-#define EDID_QUIRK_FORCE_8BPC			(1 << 8)
+-/* Force 12bpc */
+-#define EDID_QUIRK_FORCE_12BPC			(1 << 9)
+-/* Force 6bpc */
+-#define EDID_QUIRK_FORCE_6BPC			(1 << 10)
+-/* Force 10bpc */
+-#define EDID_QUIRK_FORCE_10BPC			(1 << 11)
+-/* Non desktop display (i.e. HMD) */
+-#define EDID_QUIRK_NON_DESKTOP			(1 << 12)
+-/* Cap the DSC target bitrate to 15bpp */
+-#define EDID_QUIRK_CAP_DSC_15BPP		(1 << 13)
++enum drm_edid_internal_quirk {
++	/* First detailed mode wrong, use largest 60Hz mode */
++	EDID_QUIRK_PREFER_LARGE_60 = DRM_EDID_QUIRK_NUM,
++	/* Reported 135MHz pixel clock is too high, needs adjustment */
++	EDID_QUIRK_135_CLOCK_TOO_HIGH,
++	/* Prefer the largest mode at 75 Hz */
++	EDID_QUIRK_PREFER_LARGE_75,
++	/* Detail timing is in cm not mm */
++	EDID_QUIRK_DETAILED_IN_CM,
++	/* Detailed timing descriptors have bogus size values, so just take the
++	 * maximum size and use that.
++	 */
++	EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE,
++	/* use +hsync +vsync for detailed mode */
++	EDID_QUIRK_DETAILED_SYNC_PP,
++	/* Force reduced-blanking timings for detailed modes */
++	EDID_QUIRK_FORCE_REDUCED_BLANKING,
++	/* Force 8bpc */
++	EDID_QUIRK_FORCE_8BPC,
++	/* Force 12bpc */
++	EDID_QUIRK_FORCE_12BPC,
++	/* Force 6bpc */
++	EDID_QUIRK_FORCE_6BPC,
++	/* Force 10bpc */
++	EDID_QUIRK_FORCE_10BPC,
++	/* Non desktop display (i.e. HMD) */
++	EDID_QUIRK_NON_DESKTOP,
++	/* Cap the DSC target bitrate to 15bpp */
++	EDID_QUIRK_CAP_DSC_15BPP,
++};
+ 
+ #define MICROSOFT_IEEE_OUI	0xca125c
+ 
+@@ -128,124 +130,132 @@ static const struct edid_quirk {
+ 	u32 quirks;
+ } edid_quirk_list[] = {
+ 	/* Acer AL1706 */
+-	EDID_QUIRK('A', 'C', 'R', 44358, EDID_QUIRK_PREFER_LARGE_60),
++	EDID_QUIRK('A', 'C', 'R', 44358, BIT(EDID_QUIRK_PREFER_LARGE_60)),
+ 	/* Acer F51 */
+-	EDID_QUIRK('A', 'P', 'I', 0x7602, EDID_QUIRK_PREFER_LARGE_60),
++	EDID_QUIRK('A', 'P', 'I', 0x7602, BIT(EDID_QUIRK_PREFER_LARGE_60)),
+ 
+ 	/* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
+-	EDID_QUIRK('A', 'E', 'O', 0, EDID_QUIRK_FORCE_6BPC),
++	EDID_QUIRK('A', 'E', 'O', 0, BIT(EDID_QUIRK_FORCE_6BPC)),
+ 
+ 	/* BenQ GW2765 */
+-	EDID_QUIRK('B', 'N', 'Q', 0x78d6, EDID_QUIRK_FORCE_8BPC),
++	EDID_QUIRK('B', 'N', 'Q', 0x78d6, BIT(EDID_QUIRK_FORCE_8BPC)),
+ 
+ 	/* BOE model on HP Pavilion 15-n233sl reports 8 bpc, but is a 6 bpc panel */
+-	EDID_QUIRK('B', 'O', 'E', 0x78b, EDID_QUIRK_FORCE_6BPC),
++	EDID_QUIRK('B', 'O', 'E', 0x78b, BIT(EDID_QUIRK_FORCE_6BPC)),
+ 
+ 	/* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
+-	EDID_QUIRK('C', 'P', 'T', 0x17df, EDID_QUIRK_FORCE_6BPC),
++	EDID_QUIRK('C', 'P', 'T', 0x17df, BIT(EDID_QUIRK_FORCE_6BPC)),
+ 
+ 	/* SDC panel of Lenovo B50-80 reports 8 bpc, but is a 6 bpc panel */
+-	EDID_QUIRK('S', 'D', 'C', 0x3652, EDID_QUIRK_FORCE_6BPC),
++	EDID_QUIRK('S', 'D', 'C', 0x3652, BIT(EDID_QUIRK_FORCE_6BPC)),
+ 
+ 	/* BOE model 0x0771 reports 8 bpc, but is a 6 bpc panel */
+-	EDID_QUIRK('B', 'O', 'E', 0x0771, EDID_QUIRK_FORCE_6BPC),
++	EDID_QUIRK('B', 'O', 'E', 0x0771, BIT(EDID_QUIRK_FORCE_6BPC)),
+ 
+ 	/* Belinea 10 15 55 */
+-	EDID_QUIRK('M', 'A', 'X', 1516, EDID_QUIRK_PREFER_LARGE_60),
+-	EDID_QUIRK('M', 'A', 'X', 0x77e, EDID_QUIRK_PREFER_LARGE_60),
++	EDID_QUIRK('M', 'A', 'X', 1516, BIT(EDID_QUIRK_PREFER_LARGE_60)),
++	EDID_QUIRK('M', 'A', 'X', 0x77e, BIT(EDID_QUIRK_PREFER_LARGE_60)),
+ 
+ 	/* Envision Peripherals, Inc. EN-7100e */
+-	EDID_QUIRK('E', 'P', 'I', 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH),
++	EDID_QUIRK('E', 'P', 'I', 59264, BIT(EDID_QUIRK_135_CLOCK_TOO_HIGH)),
+ 	/* Envision EN2028 */
+-	EDID_QUIRK('E', 'P', 'I', 8232, EDID_QUIRK_PREFER_LARGE_60),
++	EDID_QUIRK('E', 'P', 'I', 8232, BIT(EDID_QUIRK_PREFER_LARGE_60)),
+ 
+ 	/* Funai Electronics PM36B */
+-	EDID_QUIRK('F', 'C', 'M', 13600, EDID_QUIRK_PREFER_LARGE_75 |
+-				       EDID_QUIRK_DETAILED_IN_CM),
++	EDID_QUIRK('F', 'C', 'M', 13600, BIT(EDID_QUIRK_PREFER_LARGE_75) |
++					 BIT(EDID_QUIRK_DETAILED_IN_CM)),
+ 
+ 	/* LG 27GP950 */
+-	EDID_QUIRK('G', 'S', 'M', 0x5bbf, EDID_QUIRK_CAP_DSC_15BPP),
++	EDID_QUIRK('G', 'S', 'M', 0x5bbf, BIT(EDID_QUIRK_CAP_DSC_15BPP)),
+ 
+ 	/* LG 27GN950 */
+-	EDID_QUIRK('G', 'S', 'M', 0x5b9a, EDID_QUIRK_CAP_DSC_15BPP),
++	EDID_QUIRK('G', 'S', 'M', 0x5b9a, BIT(EDID_QUIRK_CAP_DSC_15BPP)),
+ 
+ 	/* LGD panel of HP zBook 17 G2, eDP 10 bpc, but reports unknown bpc */
+-	EDID_QUIRK('L', 'G', 'D', 764, EDID_QUIRK_FORCE_10BPC),
++	EDID_QUIRK('L', 'G', 'D', 764, BIT(EDID_QUIRK_FORCE_10BPC)),
+ 
+ 	/* LG Philips LCD LP154W01-A5 */
+-	EDID_QUIRK('L', 'P', 'L', 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE),
+-	EDID_QUIRK('L', 'P', 'L', 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE),
++	EDID_QUIRK('L', 'P', 'L', 0, BIT(EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE)),
++	EDID_QUIRK('L', 'P', 'L', 0x2a00, BIT(EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE)),
+ 
+ 	/* Samsung SyncMaster 205BW.  Note: irony */
+-	EDID_QUIRK('S', 'A', 'M', 541, EDID_QUIRK_DETAILED_SYNC_PP),
++	EDID_QUIRK('S', 'A', 'M', 541, BIT(EDID_QUIRK_DETAILED_SYNC_PP)),
+ 	/* Samsung SyncMaster 22[5-6]BW */
+-	EDID_QUIRK('S', 'A', 'M', 596, EDID_QUIRK_PREFER_LARGE_60),
+-	EDID_QUIRK('S', 'A', 'M', 638, EDID_QUIRK_PREFER_LARGE_60),
++	EDID_QUIRK('S', 'A', 'M', 596, BIT(EDID_QUIRK_PREFER_LARGE_60)),
++	EDID_QUIRK('S', 'A', 'M', 638, BIT(EDID_QUIRK_PREFER_LARGE_60)),
+ 
+ 	/* Sony PVM-2541A does up to 12 bpc, but only reports max 8 bpc */
+-	EDID_QUIRK('S', 'N', 'Y', 0x2541, EDID_QUIRK_FORCE_12BPC),
++	EDID_QUIRK('S', 'N', 'Y', 0x2541, BIT(EDID_QUIRK_FORCE_12BPC)),
+ 
+ 	/* ViewSonic VA2026w */
+-	EDID_QUIRK('V', 'S', 'C', 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING),
++	EDID_QUIRK('V', 'S', 'C', 5020, BIT(EDID_QUIRK_FORCE_REDUCED_BLANKING)),
+ 
+ 	/* Medion MD 30217 PG */
+-	EDID_QUIRK('M', 'E', 'D', 0x7b8, EDID_QUIRK_PREFER_LARGE_75),
++	EDID_QUIRK('M', 'E', 'D', 0x7b8, BIT(EDID_QUIRK_PREFER_LARGE_75)),
+ 
+ 	/* Lenovo G50 */
+-	EDID_QUIRK('S', 'D', 'C', 18514, EDID_QUIRK_FORCE_6BPC),
++	EDID_QUIRK('S', 'D', 'C', 18514, BIT(EDID_QUIRK_FORCE_6BPC)),
+ 
+ 	/* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */
+-	EDID_QUIRK('S', 'E', 'C', 0xd033, EDID_QUIRK_FORCE_8BPC),
++	EDID_QUIRK('S', 'E', 'C', 0xd033, BIT(EDID_QUIRK_FORCE_8BPC)),
+ 
+ 	/* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/
+-	EDID_QUIRK('E', 'T', 'R', 13896, EDID_QUIRK_FORCE_8BPC),
++	EDID_QUIRK('E', 'T', 'R', 13896, BIT(EDID_QUIRK_FORCE_8BPC)),
+ 
+ 	/* Valve Index Headset */
+-	EDID_QUIRK('V', 'L', 'V', 0x91a8, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b0, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b1, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b2, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b3, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b4, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b5, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b6, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b7, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b8, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91b9, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91ba, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91bb, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91bc, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91bd, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91be, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('V', 'L', 'V', 0x91bf, EDID_QUIRK_NON_DESKTOP),
++	EDID_QUIRK('V', 'L', 'V', 0x91a8, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b0, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b1, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b2, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b3, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b4, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b5, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b6, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b7, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b8, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91b9, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91ba, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91bb, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91bc, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91bd, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91be, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('V', 'L', 'V', 0x91bf, BIT(EDID_QUIRK_NON_DESKTOP)),
+ 
+ 	/* HTC Vive and Vive Pro VR Headsets */
+-	EDID_QUIRK('H', 'V', 'R', 0xaa01, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('H', 'V', 'R', 0xaa02, EDID_QUIRK_NON_DESKTOP),
++	EDID_QUIRK('H', 'V', 'R', 0xaa01, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('H', 'V', 'R', 0xaa02, BIT(EDID_QUIRK_NON_DESKTOP)),
+ 
+ 	/* Oculus Rift DK1, DK2, CV1 and Rift S VR Headsets */
+-	EDID_QUIRK('O', 'V', 'R', 0x0001, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('O', 'V', 'R', 0x0003, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('O', 'V', 'R', 0x0004, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('O', 'V', 'R', 0x0012, EDID_QUIRK_NON_DESKTOP),
++	EDID_QUIRK('O', 'V', 'R', 0x0001, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('O', 'V', 'R', 0x0003, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('O', 'V', 'R', 0x0004, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('O', 'V', 'R', 0x0012, BIT(EDID_QUIRK_NON_DESKTOP)),
+ 
+ 	/* Windows Mixed Reality Headsets */
+-	EDID_QUIRK('A', 'C', 'R', 0x7fce, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('L', 'E', 'N', 0x0408, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('F', 'U', 'J', 0x1970, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('D', 'E', 'L', 0x7fce, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('S', 'E', 'C', 0x144a, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('A', 'U', 'S', 0xc102, EDID_QUIRK_NON_DESKTOP),
++	EDID_QUIRK('A', 'C', 'R', 0x7fce, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('L', 'E', 'N', 0x0408, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('F', 'U', 'J', 0x1970, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('D', 'E', 'L', 0x7fce, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('S', 'E', 'C', 0x144a, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('A', 'U', 'S', 0xc102, BIT(EDID_QUIRK_NON_DESKTOP)),
+ 
+ 	/* Sony PlayStation VR Headset */
+-	EDID_QUIRK('S', 'N', 'Y', 0x0704, EDID_QUIRK_NON_DESKTOP),
++	EDID_QUIRK('S', 'N', 'Y', 0x0704, BIT(EDID_QUIRK_NON_DESKTOP)),
+ 
+ 	/* Sensics VR Headsets */
+-	EDID_QUIRK('S', 'E', 'N', 0x1019, EDID_QUIRK_NON_DESKTOP),
++	EDID_QUIRK('S', 'E', 'N', 0x1019, BIT(EDID_QUIRK_NON_DESKTOP)),
+ 
+ 	/* OSVR HDK and HDK2 VR Headsets */
+-	EDID_QUIRK('S', 'V', 'R', 0x1019, EDID_QUIRK_NON_DESKTOP),
+-	EDID_QUIRK('A', 'U', 'O', 0x1111, EDID_QUIRK_NON_DESKTOP),
++	EDID_QUIRK('S', 'V', 'R', 0x1019, BIT(EDID_QUIRK_NON_DESKTOP)),
++	EDID_QUIRK('A', 'U', 'O', 0x1111, BIT(EDID_QUIRK_NON_DESKTOP)),
++
++	/*
++	 * @drm_edid_internal_quirk entries end here, following with the
++	 * @drm_edid_quirk entries.
++	 */
++
++	/* HP ZR24w DP AUX DPCD access requires probing to prevent corruption. */
++	EDID_QUIRK('H', 'W', 'P', 0x2869, BIT(DRM_EDID_QUIRK_DP_DPCD_PROBE)),
+ };
+ 
+ /*
+@@ -2951,6 +2961,18 @@ static u32 edid_get_quirks(const struct drm_edid *drm_edid)
+ 	return 0;
+ }
+ 
++static bool drm_edid_has_internal_quirk(struct drm_connector *connector,
++					enum drm_edid_internal_quirk quirk)
++{
++	return connector->display_info.quirks & BIT(quirk);
++}
++
++bool drm_edid_has_quirk(struct drm_connector *connector, enum drm_edid_quirk quirk)
++{
++	return connector->display_info.quirks & BIT(quirk);
++}
++EXPORT_SYMBOL(drm_edid_has_quirk);
++
+ #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
+ #define MODE_REFRESH_DIFF(c,t) (abs((c) - (t)))
+ 
+@@ -2960,7 +2982,6 @@ static u32 edid_get_quirks(const struct drm_edid *drm_edid)
+  */
+ static void edid_fixup_preferred(struct drm_connector *connector)
+ {
+-	const struct drm_display_info *info = &connector->display_info;
+ 	struct drm_display_mode *t, *cur_mode, *preferred_mode;
+ 	int target_refresh = 0;
+ 	int cur_vrefresh, preferred_vrefresh;
+@@ -2968,9 +2989,9 @@ static void edid_fixup_preferred(struct drm_connector *connector)
+ 	if (list_empty(&connector->probed_modes))
+ 		return;
+ 
+-	if (info->quirks & EDID_QUIRK_PREFER_LARGE_60)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_PREFER_LARGE_60))
+ 		target_refresh = 60;
+-	if (info->quirks & EDID_QUIRK_PREFER_LARGE_75)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_PREFER_LARGE_75))
+ 		target_refresh = 75;
+ 
+ 	preferred_mode = list_first_entry(&connector->probed_modes,
+@@ -3474,7 +3495,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
+ 						  const struct drm_edid *drm_edid,
+ 						  const struct detailed_timing *timing)
+ {
+-	const struct drm_display_info *info = &connector->display_info;
+ 	struct drm_device *dev = connector->dev;
+ 	struct drm_display_mode *mode;
+ 	const struct detailed_pixel_timing *pt = &timing->data.pixel_data;
+@@ -3508,7 +3528,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
+ 		return NULL;
+ 	}
+ 
+-	if (info->quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) {
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_FORCE_REDUCED_BLANKING)) {
+ 		mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false);
+ 		if (!mode)
+ 			return NULL;
+@@ -3520,7 +3540,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
+ 	if (!mode)
+ 		return NULL;
+ 
+-	if (info->quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_135_CLOCK_TOO_HIGH))
+ 		mode->clock = 1088 * 10;
+ 	else
+ 		mode->clock = le16_to_cpu(timing->pixel_clock) * 10;
+@@ -3551,7 +3571,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
+ 
+ 	drm_mode_do_interlace_quirk(mode, pt);
+ 
+-	if (info->quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_DETAILED_SYNC_PP)) {
+ 		mode->flags |= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC;
+ 	} else {
+ 		mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
+@@ -3564,12 +3584,12 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
+ 	mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
+ 	mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
+ 
+-	if (info->quirks & EDID_QUIRK_DETAILED_IN_CM) {
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_DETAILED_IN_CM)) {
+ 		mode->width_mm *= 10;
+ 		mode->height_mm *= 10;
+ 	}
+ 
+-	if (info->quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE)) {
+ 		mode->width_mm = drm_edid->edid->width_cm * 10;
+ 		mode->height_mm = drm_edid->edid->height_cm * 10;
+ 	}
+@@ -6734,26 +6754,26 @@ static void update_display_info(struct drm_connector *connector,
+ 	drm_update_mso(connector, drm_edid);
+ 
+ out:
+-	if (info->quirks & EDID_QUIRK_NON_DESKTOP) {
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_NON_DESKTOP)) {
+ 		drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Non-desktop display%s\n",
+ 			    connector->base.id, connector->name,
+ 			    info->non_desktop ? " (redundant quirk)" : "");
+ 		info->non_desktop = true;
+ 	}
+ 
+-	if (info->quirks & EDID_QUIRK_CAP_DSC_15BPP)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_CAP_DSC_15BPP))
+ 		info->max_dsc_bpp = 15;
+ 
+-	if (info->quirks & EDID_QUIRK_FORCE_6BPC)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_FORCE_6BPC))
+ 		info->bpc = 6;
+ 
+-	if (info->quirks & EDID_QUIRK_FORCE_8BPC)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_FORCE_8BPC))
+ 		info->bpc = 8;
+ 
+-	if (info->quirks & EDID_QUIRK_FORCE_10BPC)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_FORCE_10BPC))
+ 		info->bpc = 10;
+ 
+-	if (info->quirks & EDID_QUIRK_FORCE_12BPC)
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_FORCE_12BPC))
+ 		info->bpc = 12;
+ 
+ 	/* Depends on info->cea_rev set by drm_parse_cea_ext() above */
+@@ -6918,7 +6938,6 @@ static int add_displayid_detailed_modes(struct drm_connector *connector,
+ static int _drm_edid_connector_add_modes(struct drm_connector *connector,
+ 					 const struct drm_edid *drm_edid)
+ {
+-	const struct drm_display_info *info = &connector->display_info;
+ 	int num_modes = 0;
+ 
+ 	if (!drm_edid)
+@@ -6948,7 +6967,8 @@ static int _drm_edid_connector_add_modes(struct drm_connector *connector,
+ 	if (drm_edid->edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ)
+ 		num_modes += add_inferred_modes(connector, drm_edid);
+ 
+-	if (info->quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
++	if (drm_edid_has_internal_quirk(connector, EDID_QUIRK_PREFER_LARGE_60) ||
++	    drm_edid_has_internal_quirk(connector, EDID_QUIRK_PREFER_LARGE_75))
+ 		edid_fixup_preferred(connector);
+ 
+ 	return num_modes;
+diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
+index 16356523816fb8..068ed911e12458 100644
+--- a/drivers/gpu/drm/i915/display/intel_display_power.c
++++ b/drivers/gpu/drm/i915/display/intel_display_power.c
+@@ -1169,7 +1169,7 @@ static void icl_mbus_init(struct intel_display *display)
+ 	if (DISPLAY_VER(display) == 12)
+ 		abox_regs |= BIT(0);
+ 
+-	for_each_set_bit(i, &abox_regs, sizeof(abox_regs))
++	for_each_set_bit(i, &abox_regs, BITS_PER_TYPE(abox_regs))
+ 		intel_de_rmw(display, MBUS_ABOX_CTL(i), mask, val);
+ }
+ 
+@@ -1630,11 +1630,11 @@ static void tgl_bw_buddy_init(struct intel_display *display)
+ 	if (table[config].page_mask == 0) {
+ 		drm_dbg_kms(display->drm,
+ 			    "Unknown memory configuration; disabling address buddy logic.\n");
+-		for_each_set_bit(i, &abox_mask, sizeof(abox_mask))
++		for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask))
+ 			intel_de_write(display, BW_BUDDY_CTL(i),
+ 				       BW_BUDDY_DISABLE);
+ 	} else {
+-		for_each_set_bit(i, &abox_mask, sizeof(abox_mask)) {
++		for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) {
+ 			intel_de_write(display, BW_BUDDY_PAGE_MASK(i),
+ 				       table[config].page_mask);
+ 
+diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+index 34131ae2c207df..3b02ed0a16dab1 100644
+--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
++++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+@@ -388,11 +388,11 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
+ 
+ 		of_id = of_match_node(mtk_drm_of_ids, node);
+ 		if (!of_id)
+-			goto next_put_node;
++			continue;
+ 
+ 		pdev = of_find_device_by_node(node);
+ 		if (!pdev)
+-			goto next_put_node;
++			continue;
+ 
+ 		drm_dev = device_find_child(&pdev->dev, NULL, mtk_drm_match);
+ 		if (!drm_dev)
+@@ -418,11 +418,10 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
+ next_put_device_pdev_dev:
+ 		put_device(&pdev->dev);
+ 
+-next_put_node:
+-		of_node_put(node);
+-
+-		if (cnt == MAX_CRTC)
++		if (cnt == MAX_CRTC) {
++			of_node_put(node);
+ 			break;
++		}
+ 	}
+ 
+ 	if (drm_priv->data->mmsys_dev_num == cnt) {
+diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c
+index 6200cad22563a3..0f4ab9e5ef95cb 100644
+--- a/drivers/gpu/drm/panthor/panthor_drv.c
++++ b/drivers/gpu/drm/panthor/panthor_drv.c
+@@ -1093,7 +1093,7 @@ static int panthor_ioctl_group_create(struct drm_device *ddev, void *data,
+ 	struct drm_panthor_queue_create *queue_args;
+ 	int ret;
+ 
+-	if (!args->queues.count)
++	if (!args->queues.count || args->queues.count > MAX_CS_PER_CSG)
+ 		return -EINVAL;
+ 
+ 	ret = PANTHOR_UOBJ_GET_ARRAY(queue_args, &args->queues);
+diff --git a/drivers/gpu/drm/xe/tests/xe_bo.c b/drivers/gpu/drm/xe/tests/xe_bo.c
+index 378dcd0fb41493..a34d1e2597b79f 100644
+--- a/drivers/gpu/drm/xe/tests/xe_bo.c
++++ b/drivers/gpu/drm/xe/tests/xe_bo.c
+@@ -236,7 +236,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
+ 		}
+ 
+ 		xe_bo_lock(external, false);
+-		err = xe_bo_pin_external(external);
++		err = xe_bo_pin_external(external, false);
+ 		xe_bo_unlock(external);
+ 		if (err) {
+ 			KUNIT_FAIL(test, "external bo pin err=%pe\n",
+diff --git a/drivers/gpu/drm/xe/tests/xe_dma_buf.c b/drivers/gpu/drm/xe/tests/xe_dma_buf.c
+index c53f67ce4b0aa2..121f17c112ec6a 100644
+--- a/drivers/gpu/drm/xe/tests/xe_dma_buf.c
++++ b/drivers/gpu/drm/xe/tests/xe_dma_buf.c
+@@ -89,15 +89,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
+ 		return;
+ 	}
+ 
+-	/*
+-	 * If on different devices, the exporter is kept in system  if
+-	 * possible, saving a migration step as the transfer is just
+-	 * likely as fast from system memory.
+-	 */
+-	if (params->mem_mask & XE_BO_FLAG_SYSTEM)
+-		KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, XE_PL_TT));
+-	else
+-		KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type));
++	KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type));
+ 
+ 	if (params->force_different_devices)
+ 		KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(imported, XE_PL_TT));
+diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
+index 50326e756f8975..5390f535394695 100644
+--- a/drivers/gpu/drm/xe/xe_bo.c
++++ b/drivers/gpu/drm/xe/xe_bo.c
+@@ -184,6 +184,8 @@ static void try_add_system(struct xe_device *xe, struct xe_bo *bo,
+ 
+ 		bo->placements[*c] = (struct ttm_place) {
+ 			.mem_type = XE_PL_TT,
++			.flags = (bo_flags & XE_BO_FLAG_VRAM_MASK) ?
++			TTM_PL_FLAG_FALLBACK : 0,
+ 		};
+ 		*c += 1;
+ 	}
+@@ -2266,6 +2268,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
+ /**
+  * xe_bo_pin_external - pin an external BO
+  * @bo: buffer object to be pinned
++ * @in_place: Pin in current placement, don't attempt to migrate.
+  *
+  * Pin an external (not tied to a VM, can be exported via dma-buf / prime FD)
+  * BO. Unique call compared to xe_bo_pin as this function has it own set of
+@@ -2273,7 +2276,7 @@ uint64_t vram_region_gpu_offset(struct ttm_resource *res)
+  *
+  * Returns 0 for success, negative error code otherwise.
+  */
+-int xe_bo_pin_external(struct xe_bo *bo)
++int xe_bo_pin_external(struct xe_bo *bo, bool in_place)
+ {
+ 	struct xe_device *xe = xe_bo_device(bo);
+ 	int err;
+@@ -2282,9 +2285,11 @@ int xe_bo_pin_external(struct xe_bo *bo)
+ 	xe_assert(xe, xe_bo_is_user(bo));
+ 
+ 	if (!xe_bo_is_pinned(bo)) {
+-		err = xe_bo_validate(bo, NULL, false);
+-		if (err)
+-			return err;
++		if (!in_place) {
++			err = xe_bo_validate(bo, NULL, false);
++			if (err)
++				return err;
++		}
+ 
+ 		spin_lock(&xe->pinned.lock);
+ 		list_add_tail(&bo->pinned_link, &xe->pinned.late.external);
+@@ -2437,6 +2442,9 @@ int xe_bo_validate(struct xe_bo *bo, struct xe_vm *vm, bool allow_res_evict)
+ 	};
+ 	int ret;
+ 
++	if (xe_bo_is_pinned(bo))
++		return 0;
++
+ 	if (vm) {
+ 		lockdep_assert_held(&vm->lock);
+ 		xe_vm_assert_held(vm);
+diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
+index 02ada1fb8a2359..bf0432c360bbba 100644
+--- a/drivers/gpu/drm/xe/xe_bo.h
++++ b/drivers/gpu/drm/xe/xe_bo.h
+@@ -201,7 +201,7 @@ static inline void xe_bo_unlock_vm_held(struct xe_bo *bo)
+ 	}
+ }
+ 
+-int xe_bo_pin_external(struct xe_bo *bo);
++int xe_bo_pin_external(struct xe_bo *bo, bool in_place);
+ int xe_bo_pin(struct xe_bo *bo);
+ void xe_bo_unpin_external(struct xe_bo *bo);
+ void xe_bo_unpin(struct xe_bo *bo);
+diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
+index 6383a1c0d47847..1db2aba4738c23 100644
+--- a/drivers/gpu/drm/xe/xe_device_types.h
++++ b/drivers/gpu/drm/xe/xe_device_types.h
+@@ -529,6 +529,12 @@ struct xe_device {
+ 
+ 	/** @pm_notifier: Our PM notifier to perform actions in response to various PM events. */
+ 	struct notifier_block pm_notifier;
++	/** @pm_block: Completion to block validating tasks on suspend / hibernate prepare */
++	struct completion pm_block;
++	/** @rebind_resume_list: List of wq items to kick on resume. */
++	struct list_head rebind_resume_list;
++	/** @rebind_resume_lock: Lock to protect the rebind_resume_list */
++	struct mutex rebind_resume_lock;
+ 
+ 	/** @pmt: Support the PMT driver callback interface */
+ 	struct {
+diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c b/drivers/gpu/drm/xe/xe_dma_buf.c
+index 346f857f38374f..af64baf872ef7b 100644
+--- a/drivers/gpu/drm/xe/xe_dma_buf.c
++++ b/drivers/gpu/drm/xe/xe_dma_buf.c
+@@ -72,7 +72,7 @@ static int xe_dma_buf_pin(struct dma_buf_attachment *attach)
+ 		return ret;
+ 	}
+ 
+-	ret = xe_bo_pin_external(bo);
++	ret = xe_bo_pin_external(bo, true);
+ 	xe_assert(xe, !ret);
+ 
+ 	return 0;
+diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
+index 44364c042ad72d..374c831e691b2b 100644
+--- a/drivers/gpu/drm/xe/xe_exec.c
++++ b/drivers/gpu/drm/xe/xe_exec.c
+@@ -237,6 +237,15 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
+ 		goto err_unlock_list;
+ 	}
+ 
++	/*
++	 * It's OK to block interruptible here with the vm lock held, since
++	 * on task freezing during suspend / hibernate, the call will
++	 * return -ERESTARTSYS and the IOCTL will be rerun.
++	 */
++	err = wait_for_completion_interruptible(&xe->pm_block);
++	if (err)
++		goto err_unlock_list;
++
+ 	vm_exec.vm = &vm->gpuvm;
+ 	vm_exec.flags = DRM_EXEC_INTERRUPTIBLE_WAIT;
+ 	if (xe_vm_in_lr_mode(vm)) {
+diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
+index ad263de44111d4..375a197a86089b 100644
+--- a/drivers/gpu/drm/xe/xe_pm.c
++++ b/drivers/gpu/drm/xe/xe_pm.c
+@@ -23,6 +23,7 @@
+ #include "xe_pcode.h"
+ #include "xe_pxp.h"
+ #include "xe_trace.h"
++#include "xe_vm.h"
+ #include "xe_wa.h"
+ 
+ /**
+@@ -285,6 +286,19 @@ static u32 vram_threshold_value(struct xe_device *xe)
+ 	return DEFAULT_VRAM_THRESHOLD;
+ }
+ 
++static void xe_pm_wake_rebind_workers(struct xe_device *xe)
++{
++	struct xe_vm *vm, *next;
++
++	mutex_lock(&xe->rebind_resume_lock);
++	list_for_each_entry_safe(vm, next, &xe->rebind_resume_list,
++				 preempt.pm_activate_link) {
++		list_del_init(&vm->preempt.pm_activate_link);
++		xe_vm_resume_rebind_worker(vm);
++	}
++	mutex_unlock(&xe->rebind_resume_lock);
++}
++
+ static int xe_pm_notifier_callback(struct notifier_block *nb,
+ 				   unsigned long action, void *data)
+ {
+@@ -294,30 +308,30 @@ static int xe_pm_notifier_callback(struct notifier_block *nb,
+ 	switch (action) {
+ 	case PM_HIBERNATION_PREPARE:
+ 	case PM_SUSPEND_PREPARE:
++		reinit_completion(&xe->pm_block);
+ 		xe_pm_runtime_get(xe);
+ 		err = xe_bo_evict_all_user(xe);
+-		if (err) {
++		if (err)
+ 			drm_dbg(&xe->drm, "Notifier evict user failed (%d)\n", err);
+-			xe_pm_runtime_put(xe);
+-			break;
+-		}
+ 
+ 		err = xe_bo_notifier_prepare_all_pinned(xe);
+-		if (err) {
++		if (err)
+ 			drm_dbg(&xe->drm, "Notifier prepare pin failed (%d)\n", err);
+-			xe_pm_runtime_put(xe);
+-		}
++		/*
++		 * Keep the runtime pm reference until post hibernation / post suspend to
++		 * avoid a runtime suspend interfering with evicted objects or backup
++		 * allocations.
++		 */
+ 		break;
+ 	case PM_POST_HIBERNATION:
+ 	case PM_POST_SUSPEND:
++		complete_all(&xe->pm_block);
++		xe_pm_wake_rebind_workers(xe);
+ 		xe_bo_notifier_unprepare_all_pinned(xe);
+ 		xe_pm_runtime_put(xe);
+ 		break;
+ 	}
+ 
+-	if (err)
+-		return NOTIFY_BAD;
+-
+ 	return NOTIFY_DONE;
+ }
+ 
+@@ -339,6 +353,14 @@ int xe_pm_init(struct xe_device *xe)
+ 	if (err)
+ 		return err;
+ 
++	err = drmm_mutex_init(&xe->drm, &xe->rebind_resume_lock);
++	if (err)
++		goto err_unregister;
++
++	init_completion(&xe->pm_block);
++	complete_all(&xe->pm_block);
++	INIT_LIST_HEAD(&xe->rebind_resume_list);
++
+ 	/* For now suspend/resume is only allowed with GuC */
+ 	if (!xe_device_uc_enabled(xe))
+ 		return 0;
+diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c
+index 1f710b3fc599b5..5ae3d70e45167f 100644
+--- a/drivers/gpu/drm/xe/xe_survivability_mode.c
++++ b/drivers/gpu/drm/xe/xe_survivability_mode.c
+@@ -40,6 +40,8 @@
+  *
+  *	# echo 1 > /sys/kernel/config/xe/0000:03:00.0/survivability_mode
+  *
++ * It is the responsibility of the user to clear the mode once firmware flash is complete.
++ *
+  * Refer :ref:`xe_configfs` for more details on how to use configfs
+  *
+  * Survivability mode is indicated by the below admin-only readable sysfs which provides additional
+@@ -146,7 +148,6 @@ static void xe_survivability_mode_fini(void *arg)
+ 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
+ 	struct device *dev = &pdev->dev;
+ 
+-	xe_configfs_clear_survivability_mode(pdev);
+ 	sysfs_remove_file(&dev->kobj, &dev_attr_survivability_mode.attr);
+ }
+ 
+diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
+index e278aad1a6eb29..84052b98002d14 100644
+--- a/drivers/gpu/drm/xe/xe_vm.c
++++ b/drivers/gpu/drm/xe/xe_vm.c
+@@ -393,6 +393,9 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
+ 		list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind,
+ 			       &vm->rebind_list);
+ 
++	if (!try_wait_for_completion(&vm->xe->pm_block))
++		return -EAGAIN;
++
+ 	ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false);
+ 	if (ret)
+ 		return ret;
+@@ -479,6 +482,33 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
+ 	return xe_vm_validate_rebind(vm, exec, vm->preempt.num_exec_queues);
+ }
+ 
++static bool vm_suspend_rebind_worker(struct xe_vm *vm)
++{
++	struct xe_device *xe = vm->xe;
++	bool ret = false;
++
++	mutex_lock(&xe->rebind_resume_lock);
++	if (!try_wait_for_completion(&vm->xe->pm_block)) {
++		ret = true;
++		list_move_tail(&vm->preempt.pm_activate_link, &xe->rebind_resume_list);
++	}
++	mutex_unlock(&xe->rebind_resume_lock);
++
++	return ret;
++}
++
++/**
++ * xe_vm_resume_rebind_worker() - Resume the rebind worker.
++ * @vm: The vm whose preempt worker to resume.
++ *
++ * Resume a preempt worker that was previously suspended by
++ * vm_suspend_rebind_worker().
++ */
++void xe_vm_resume_rebind_worker(struct xe_vm *vm)
++{
++	queue_work(vm->xe->ordered_wq, &vm->preempt.rebind_work);
++}
++
+ static void preempt_rebind_work_func(struct work_struct *w)
+ {
+ 	struct xe_vm *vm = container_of(w, struct xe_vm, preempt.rebind_work);
+@@ -502,6 +532,11 @@ static void preempt_rebind_work_func(struct work_struct *w)
+ 	}
+ 
+ retry:
++	if (!try_wait_for_completion(&vm->xe->pm_block) && vm_suspend_rebind_worker(vm)) {
++		up_write(&vm->lock);
++		return;
++	}
++
+ 	if (xe_vm_userptr_check_repin(vm)) {
+ 		err = xe_vm_userptr_pin(vm);
+ 		if (err)
+@@ -1686,6 +1721,7 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef)
+ 	if (flags & XE_VM_FLAG_LR_MODE) {
+ 		INIT_WORK(&vm->preempt.rebind_work, preempt_rebind_work_func);
+ 		xe_pm_runtime_get_noresume(xe);
++		INIT_LIST_HEAD(&vm->preempt.pm_activate_link);
+ 	}
+ 
+ 	if (flags & XE_VM_FLAG_FAULT_MODE) {
+@@ -1867,8 +1903,12 @@ void xe_vm_close_and_put(struct xe_vm *vm)
+ 	xe_assert(xe, !vm->preempt.num_exec_queues);
+ 
+ 	xe_vm_close(vm);
+-	if (xe_vm_in_preempt_fence_mode(vm))
++	if (xe_vm_in_preempt_fence_mode(vm)) {
++		mutex_lock(&xe->rebind_resume_lock);
++		list_del_init(&vm->preempt.pm_activate_link);
++		mutex_unlock(&xe->rebind_resume_lock);
+ 		flush_work(&vm->preempt.rebind_work);
++	}
+ 	if (xe_vm_in_fault_mode(vm))
+ 		xe_svm_close(vm);
+ 
+diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h
+index e54ca835b58282..e493a17e0f19d9 100644
+--- a/drivers/gpu/drm/xe/xe_vm.h
++++ b/drivers/gpu/drm/xe/xe_vm.h
+@@ -268,6 +268,8 @@ struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo,
+ 				       struct xe_exec_queue *q, u64 addr,
+ 				       enum xe_cache_level cache_lvl);
+ 
++void xe_vm_resume_rebind_worker(struct xe_vm *vm);
++
+ /**
+  * xe_vm_resv() - Return's the vm's reservation object
+  * @vm: The vm
+diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
+index 1979e9bdbdf36b..4ebd3dc53f3c1a 100644
+--- a/drivers/gpu/drm/xe/xe_vm_types.h
++++ b/drivers/gpu/drm/xe/xe_vm_types.h
+@@ -286,6 +286,11 @@ struct xe_vm {
+ 		 * BOs
+ 		 */
+ 		struct work_struct rebind_work;
++		/**
++		 * @preempt.pm_activate_link: Link to list of rebind workers to be
++		 * kicked on resume.
++		 */
++		struct list_head pm_activate_link;
+ 	} preempt;
+ 
+ 	/** @um: unified memory state */
+diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
+index a7f89946dad418..e94ac746a741af 100644
+--- a/drivers/i2c/busses/i2c-i801.c
++++ b/drivers/i2c/busses/i2c-i801.c
+@@ -1052,7 +1052,7 @@ static const struct pci_device_id i801_ids[] = {
+ 	{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
+ 	{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS,	FEATURES_ICH5 | FEATURE_TCO_CNL) },
+ 	{ PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS,	FEATURES_ICH5 | FEATURE_TCO_CNL) },
+-	{ PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
++	{ PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS,		FEATURES_ICH5)			 },
+ 	{ PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
+ 	{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
+ 	{ PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS,		FEATURES_ICH5 | FEATURE_TCO_CNL) },
+diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
+index cfafe089102aa2..9e1f71fed0feac 100644
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -99,6 +99,9 @@ static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c
+ {
+ 	u32 val, mask;
+ 
++	if (len < 1 || len > 16)
++		return -EINVAL;
++
+ 	val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS;
+ 	mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK;
+ 
+@@ -222,15 +225,6 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
+ 	}
+ 
+ 	switch (size) {
+-	case I2C_SMBUS_QUICK:
+-		ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
+-		if (ret)
+-			goto out_unlock;
+-		ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
+-		if (ret)
+-			goto out_unlock;
+-		break;
+-
+ 	case I2C_SMBUS_BYTE:
+ 		if (read_write == I2C_SMBUS_WRITE) {
+ 			ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
+@@ -312,9 +306,9 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
+ 
+ static u32 rtl9300_i2c_func(struct i2c_adapter *a)
+ {
+-	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+-	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+-	       I2C_FUNC_SMBUS_BLOCK_DATA;
++	return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
++	       I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
++	       I2C_FUNC_SMBUS_I2C_BLOCK;
+ }
+ 
+ static const struct i2c_algorithm rtl9300_i2c_algo = {
+@@ -323,7 +317,7 @@ static const struct i2c_algorithm rtl9300_i2c_algo = {
+ };
+ 
+ static struct i2c_adapter_quirks rtl9300_i2c_quirks = {
+-	.flags		= I2C_AQ_NO_CLK_STRETCH,
++	.flags		= I2C_AQ_NO_CLK_STRETCH | I2C_AQ_NO_ZERO_LEN,
+ 	.max_read_len	= 16,
+ 	.max_write_len	= 16,
+ };
+@@ -353,7 +347,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
+ 
+ 	platform_set_drvdata(pdev, i2c);
+ 
+-	if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN)
++	if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN)
+ 		return dev_err_probe(dev, -EINVAL, "Too many channels\n");
+ 
+ 	device_for_each_child_node(dev, child) {
+diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
+index 1d8c579b54331e..4ee9e403d38501 100644
+--- a/drivers/input/joystick/xpad.c
++++ b/drivers/input/joystick/xpad.c
+@@ -422,6 +422,7 @@ static const struct xpad_device {
+ 	{ 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE },
+ 	{ 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT },
+ 	{ 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX },
++	{ 0x37d7, 0x2501, "Flydigi Apex 5", 0, XTYPE_XBOX360 },
+ 	{ 0x413d, 0x2104, "Black Shark Green Ghost Gamepad", 0, XTYPE_XBOX360 },
+ 	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
+ 	{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
+@@ -578,6 +579,7 @@ static const struct usb_device_id xpad_table[] = {
+ 	XPAD_XBOX360_VENDOR(0x3537),		/* GameSir Controllers */
+ 	XPAD_XBOXONE_VENDOR(0x3537),		/* GameSir Controllers */
+ 	XPAD_XBOXONE_VENDOR(0x366c),		/* ByoWave controllers */
++	XPAD_XBOX360_VENDOR(0x37d7),		/* Flydigi Controllers */
+ 	XPAD_XBOX360_VENDOR(0x413d),		/* Black Shark Green Ghost Controller */
+ 	{ }
+ };
+diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c
+index 6fac31c0d99f2b..ff23219a582ab8 100644
+--- a/drivers/input/misc/iqs7222.c
++++ b/drivers/input/misc/iqs7222.c
+@@ -2427,6 +2427,9 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
+ 		if (error)
+ 			return error;
+ 
++		if (!iqs7222->kp_type[chan_index][i])
++			continue;
++
+ 		if (!dev_desc->event_offset)
+ 			continue;
+ 
+diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
+index 6ed9fc34948cbe..1caa6c4ca435c7 100644
+--- a/drivers/input/serio/i8042-acpipnpio.h
++++ b/drivers/input/serio/i8042-acpipnpio.h
+@@ -1155,6 +1155,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)
+ 	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
++		},
++		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
++					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
++	},
++	{
++		.matches = {
++			DMI_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
++		},
++		.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
++					SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
++	},
+ 	/*
+ 	 * A lot of modern Clevo barebones have touchpad and/or keyboard issues
+ 	 * after suspend fixable with the forcenorestore quirk.
+diff --git a/drivers/iommu/intel/cache.c b/drivers/iommu/intel/cache.c
+index c8b79de84d3fb9..071f78e67fcba0 100644
+--- a/drivers/iommu/intel/cache.c
++++ b/drivers/iommu/intel/cache.c
+@@ -370,7 +370,7 @@ static void cache_tag_flush_iotlb(struct dmar_domain *domain, struct cache_tag *
+ 	struct intel_iommu *iommu = tag->iommu;
+ 	u64 type = DMA_TLB_PSI_FLUSH;
+ 
+-	if (domain->use_first_level) {
++	if (intel_domain_is_fs_paging(domain)) {
+ 		qi_batch_add_piotlb(iommu, tag->domain_id, tag->pasid, addr,
+ 				    pages, ih, domain->qi_batch);
+ 		return;
+@@ -529,7 +529,8 @@ void cache_tag_flush_range_np(struct dmar_domain *domain, unsigned long start,
+ 			qi_batch_flush_descs(iommu, domain->qi_batch);
+ 		iommu = tag->iommu;
+ 
+-		if (!cap_caching_mode(iommu->cap) || domain->use_first_level) {
++		if (!cap_caching_mode(iommu->cap) ||
++		    intel_domain_is_fs_paging(domain)) {
+ 			iommu_flush_write_buffer(iommu);
+ 			continue;
+ 		}
+diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
+index c239e280e43d91..34dd175a331dc7 100644
+--- a/drivers/iommu/intel/iommu.c
++++ b/drivers/iommu/intel/iommu.c
+@@ -57,6 +57,8 @@
+ static void __init check_tylersburg_isoch(void);
+ static int rwbf_quirk;
+ 
++#define rwbf_required(iommu)	(rwbf_quirk || cap_rwbf((iommu)->cap))
++
+ /*
+  * set to 1 to panic kernel if can't successfully enable VT-d
+  * (used when kernel is launched w/ TXT)
+@@ -1479,6 +1481,9 @@ static int domain_context_mapping_one(struct dmar_domain *domain,
+ 	struct context_entry *context;
+ 	int ret;
+ 
++	if (WARN_ON(!intel_domain_is_ss_paging(domain)))
++		return -EINVAL;
++
+ 	pr_debug("Set context mapping for %02x:%02x.%d\n",
+ 		bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ 
+@@ -1795,18 +1800,6 @@ static int domain_setup_first_level(struct intel_iommu *iommu,
+ 					  (pgd_t *)pgd, flags, old);
+ }
+ 
+-static bool domain_need_iotlb_sync_map(struct dmar_domain *domain,
+-				       struct intel_iommu *iommu)
+-{
+-	if (cap_caching_mode(iommu->cap) && !domain->use_first_level)
+-		return true;
+-
+-	if (rwbf_quirk || cap_rwbf(iommu->cap))
+-		return true;
+-
+-	return false;
+-}
+-
+ static int dmar_domain_attach_device(struct dmar_domain *domain,
+ 				     struct device *dev)
+ {
+@@ -1830,12 +1823,14 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
+ 
+ 	if (!sm_supported(iommu))
+ 		ret = domain_context_mapping(domain, dev);
+-	else if (domain->use_first_level)
++	else if (intel_domain_is_fs_paging(domain))
+ 		ret = domain_setup_first_level(iommu, domain, dev,
+ 					       IOMMU_NO_PASID, NULL);
+-	else
++	else if (intel_domain_is_ss_paging(domain))
+ 		ret = domain_setup_second_level(iommu, domain, dev,
+ 						IOMMU_NO_PASID, NULL);
++	else if (WARN_ON(true))
++		ret = -EINVAL;
+ 
+ 	if (ret)
+ 		goto out_block_translation;
+@@ -1844,8 +1839,6 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
+ 	if (ret)
+ 		goto out_block_translation;
+ 
+-	domain->iotlb_sync_map |= domain_need_iotlb_sync_map(domain, iommu);
+-
+ 	return 0;
+ 
+ out_block_translation:
+@@ -3299,10 +3292,14 @@ static struct dmar_domain *paging_domain_alloc(struct device *dev, bool first_st
+ 	spin_lock_init(&domain->lock);
+ 	spin_lock_init(&domain->cache_lock);
+ 	xa_init(&domain->iommu_array);
++	INIT_LIST_HEAD(&domain->s1_domains);
++	spin_lock_init(&domain->s1_lock);
+ 
+ 	domain->nid = dev_to_node(dev);
+ 	domain->use_first_level = first_stage;
+ 
++	domain->domain.type = IOMMU_DOMAIN_UNMANAGED;
++
+ 	/* calculate the address width */
+ 	addr_width = agaw_to_width(iommu->agaw);
+ 	if (addr_width > cap_mgaw(iommu->cap))
+@@ -3344,62 +3341,92 @@ static struct dmar_domain *paging_domain_alloc(struct device *dev, bool first_st
+ }
+ 
+ static struct iommu_domain *
+-intel_iommu_domain_alloc_paging_flags(struct device *dev, u32 flags,
+-				      const struct iommu_user_data *user_data)
++intel_iommu_domain_alloc_first_stage(struct device *dev,
++				     struct intel_iommu *iommu, u32 flags)
++{
++	struct dmar_domain *dmar_domain;
++
++	if (flags & ~IOMMU_HWPT_ALLOC_PASID)
++		return ERR_PTR(-EOPNOTSUPP);
++
++	/* Only SL is available in legacy mode */
++	if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
++		return ERR_PTR(-EOPNOTSUPP);
++
++	dmar_domain = paging_domain_alloc(dev, true);
++	if (IS_ERR(dmar_domain))
++		return ERR_CAST(dmar_domain);
++
++	dmar_domain->domain.ops = &intel_fs_paging_domain_ops;
++	/*
++	 * iotlb sync for map is only needed for legacy implementations that
++	 * explicitly require flushing internal write buffers to ensure memory
++	 * coherence.
++	 */
++	if (rwbf_required(iommu))
++		dmar_domain->iotlb_sync_map = true;
++
++	return &dmar_domain->domain;
++}
++
++static struct iommu_domain *
++intel_iommu_domain_alloc_second_stage(struct device *dev,
++				      struct intel_iommu *iommu, u32 flags)
+ {
+-	struct device_domain_info *info = dev_iommu_priv_get(dev);
+-	bool dirty_tracking = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
+-	bool nested_parent = flags & IOMMU_HWPT_ALLOC_NEST_PARENT;
+-	struct intel_iommu *iommu = info->iommu;
+ 	struct dmar_domain *dmar_domain;
+-	struct iommu_domain *domain;
+-	bool first_stage;
+ 
+ 	if (flags &
+ 	    (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING |
+ 	       IOMMU_HWPT_ALLOC_PASID)))
+ 		return ERR_PTR(-EOPNOTSUPP);
+-	if (nested_parent && !nested_supported(iommu))
++
++	if (((flags & IOMMU_HWPT_ALLOC_NEST_PARENT) &&
++	     !nested_supported(iommu)) ||
++	    ((flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING) &&
++	     !ssads_supported(iommu)))
+ 		return ERR_PTR(-EOPNOTSUPP);
+-	if (user_data || (dirty_tracking && !ssads_supported(iommu)))
++
++	/* Legacy mode always supports second stage */
++	if (sm_supported(iommu) && !ecap_slts(iommu->ecap))
+ 		return ERR_PTR(-EOPNOTSUPP);
+ 
++	dmar_domain = paging_domain_alloc(dev, false);
++	if (IS_ERR(dmar_domain))
++		return ERR_CAST(dmar_domain);
++
++	dmar_domain->domain.ops = &intel_ss_paging_domain_ops;
++	dmar_domain->nested_parent = flags & IOMMU_HWPT_ALLOC_NEST_PARENT;
++
++	if (flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING)
++		dmar_domain->domain.dirty_ops = &intel_dirty_ops;
++
+ 	/*
+-	 * Always allocate the guest compatible page table unless
+-	 * IOMMU_HWPT_ALLOC_NEST_PARENT or IOMMU_HWPT_ALLOC_DIRTY_TRACKING
+-	 * is specified.
++	 * Besides the internal write buffer flush, the caching mode used for
++	 * legacy nested translation (which utilizes shadowing page tables)
++	 * also requires iotlb sync on map.
+ 	 */
+-	if (nested_parent || dirty_tracking) {
+-		if (!sm_supported(iommu) || !ecap_slts(iommu->ecap))
+-			return ERR_PTR(-EOPNOTSUPP);
+-		first_stage = false;
+-	} else {
+-		first_stage = first_level_by_default(iommu);
+-	}
++	if (rwbf_required(iommu) || cap_caching_mode(iommu->cap))
++		dmar_domain->iotlb_sync_map = true;
+ 
+-	dmar_domain = paging_domain_alloc(dev, first_stage);
+-	if (IS_ERR(dmar_domain))
+-		return ERR_CAST(dmar_domain);
+-	domain = &dmar_domain->domain;
+-	domain->type = IOMMU_DOMAIN_UNMANAGED;
+-	domain->owner = &intel_iommu_ops;
+-	domain->ops = intel_iommu_ops.default_domain_ops;
+-
+-	if (nested_parent) {
+-		dmar_domain->nested_parent = true;
+-		INIT_LIST_HEAD(&dmar_domain->s1_domains);
+-		spin_lock_init(&dmar_domain->s1_lock);
+-	}
++	return &dmar_domain->domain;
++}
+ 
+-	if (dirty_tracking) {
+-		if (dmar_domain->use_first_level) {
+-			iommu_domain_free(domain);
+-			return ERR_PTR(-EOPNOTSUPP);
+-		}
+-		domain->dirty_ops = &intel_dirty_ops;
+-	}
++static struct iommu_domain *
++intel_iommu_domain_alloc_paging_flags(struct device *dev, u32 flags,
++				      const struct iommu_user_data *user_data)
++{
++	struct device_domain_info *info = dev_iommu_priv_get(dev);
++	struct intel_iommu *iommu = info->iommu;
++	struct iommu_domain *domain;
+ 
+-	return domain;
++	if (user_data)
++		return ERR_PTR(-EOPNOTSUPP);
++
++	/* Prefer first stage if possible by default. */
++	domain = intel_iommu_domain_alloc_first_stage(dev, iommu, flags);
++	if (domain != ERR_PTR(-EOPNOTSUPP))
++		return domain;
++	return intel_iommu_domain_alloc_second_stage(dev, iommu, flags);
+ }
+ 
+ static void intel_iommu_domain_free(struct iommu_domain *domain)
+@@ -3411,33 +3438,86 @@ static void intel_iommu_domain_free(struct iommu_domain *domain)
+ 	domain_exit(dmar_domain);
+ }
+ 
++static int paging_domain_compatible_first_stage(struct dmar_domain *dmar_domain,
++						struct intel_iommu *iommu)
++{
++	if (WARN_ON(dmar_domain->domain.dirty_ops ||
++		    dmar_domain->nested_parent))
++		return -EINVAL;
++
++	/* Only SL is available in legacy mode */
++	if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
++		return -EINVAL;
++
++	/* Same page size support */
++	if (!cap_fl1gp_support(iommu->cap) &&
++	    (dmar_domain->domain.pgsize_bitmap & SZ_1G))
++		return -EINVAL;
++
++	/* iotlb sync on map requirement */
++	if ((rwbf_required(iommu)) && !dmar_domain->iotlb_sync_map)
++		return -EINVAL;
++
++	return 0;
++}
++
++static int
++paging_domain_compatible_second_stage(struct dmar_domain *dmar_domain,
++				      struct intel_iommu *iommu)
++{
++	unsigned int sslps = cap_super_page_val(iommu->cap);
++
++	if (dmar_domain->domain.dirty_ops && !ssads_supported(iommu))
++		return -EINVAL;
++	if (dmar_domain->nested_parent && !nested_supported(iommu))
++		return -EINVAL;
++
++	/* Legacy mode always supports second stage */
++	if (sm_supported(iommu) && !ecap_slts(iommu->ecap))
++		return -EINVAL;
++
++	/* Same page size support */
++	if (!(sslps & BIT(0)) && (dmar_domain->domain.pgsize_bitmap & SZ_2M))
++		return -EINVAL;
++	if (!(sslps & BIT(1)) && (dmar_domain->domain.pgsize_bitmap & SZ_1G))
++		return -EINVAL;
++
++	/* iotlb sync on map requirement */
++	if ((rwbf_required(iommu) || cap_caching_mode(iommu->cap)) &&
++	    !dmar_domain->iotlb_sync_map)
++		return -EINVAL;
++
++	return 0;
++}
++
+ int paging_domain_compatible(struct iommu_domain *domain, struct device *dev)
+ {
+ 	struct device_domain_info *info = dev_iommu_priv_get(dev);
+ 	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+ 	struct intel_iommu *iommu = info->iommu;
++	int ret = -EINVAL;
+ 	int addr_width;
+ 
+-	if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING)))
+-		return -EPERM;
++	if (intel_domain_is_fs_paging(dmar_domain))
++		ret = paging_domain_compatible_first_stage(dmar_domain, iommu);
++	else if (intel_domain_is_ss_paging(dmar_domain))
++		ret = paging_domain_compatible_second_stage(dmar_domain, iommu);
++	else if (WARN_ON(true))
++		ret = -EINVAL;
++	if (ret)
++		return ret;
+ 
++	/*
++	 * FIXME this is locked wrong, it needs to be under the
++	 * dmar_domain->lock
++	 */
+ 	if (dmar_domain->force_snooping && !ecap_sc_support(iommu->ecap))
+ 		return -EINVAL;
+ 
+-	if (domain->dirty_ops && !ssads_supported(iommu))
+-		return -EINVAL;
+-
+ 	if (dmar_domain->iommu_coherency !=
+ 			iommu_paging_structure_coherency(iommu))
+ 		return -EINVAL;
+ 
+-	if (dmar_domain->iommu_superpage !=
+-			iommu_superpage_capability(iommu, dmar_domain->use_first_level))
+-		return -EINVAL;
+-
+-	if (dmar_domain->use_first_level &&
+-	    (!sm_supported(iommu) || !ecap_flts(iommu->ecap)))
+-		return -EINVAL;
+ 
+ 	/* check if this iommu agaw is sufficient for max mapped address */
+ 	addr_width = agaw_to_width(iommu->agaw);
+@@ -4094,12 +4174,15 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
+ 	if (ret)
+ 		goto out_remove_dev_pasid;
+ 
+-	if (dmar_domain->use_first_level)
++	if (intel_domain_is_fs_paging(dmar_domain))
+ 		ret = domain_setup_first_level(iommu, dmar_domain,
+ 					       dev, pasid, old);
+-	else
++	else if (intel_domain_is_ss_paging(dmar_domain))
+ 		ret = domain_setup_second_level(iommu, dmar_domain,
+ 						dev, pasid, old);
++	else if (WARN_ON(true))
++		ret = -EINVAL;
++
+ 	if (ret)
+ 		goto out_unwind_iopf;
+ 
+@@ -4374,6 +4457,32 @@ static struct iommu_domain identity_domain = {
+ 	},
+ };
+ 
++const struct iommu_domain_ops intel_fs_paging_domain_ops = {
++	.attach_dev = intel_iommu_attach_device,
++	.set_dev_pasid = intel_iommu_set_dev_pasid,
++	.map_pages = intel_iommu_map_pages,
++	.unmap_pages = intel_iommu_unmap_pages,
++	.iotlb_sync_map = intel_iommu_iotlb_sync_map,
++	.flush_iotlb_all = intel_flush_iotlb_all,
++	.iotlb_sync = intel_iommu_tlb_sync,
++	.iova_to_phys = intel_iommu_iova_to_phys,
++	.free = intel_iommu_domain_free,
++	.enforce_cache_coherency = intel_iommu_enforce_cache_coherency,
++};
++
++const struct iommu_domain_ops intel_ss_paging_domain_ops = {
++	.attach_dev = intel_iommu_attach_device,
++	.set_dev_pasid = intel_iommu_set_dev_pasid,
++	.map_pages = intel_iommu_map_pages,
++	.unmap_pages = intel_iommu_unmap_pages,
++	.iotlb_sync_map = intel_iommu_iotlb_sync_map,
++	.flush_iotlb_all = intel_flush_iotlb_all,
++	.iotlb_sync = intel_iommu_tlb_sync,
++	.iova_to_phys = intel_iommu_iova_to_phys,
++	.free = intel_iommu_domain_free,
++	.enforce_cache_coherency = intel_iommu_enforce_cache_coherency,
++};
++
+ const struct iommu_ops intel_iommu_ops = {
+ 	.blocked_domain		= &blocking_domain,
+ 	.release_domain		= &blocking_domain,
+@@ -4391,18 +4500,6 @@ const struct iommu_ops intel_iommu_ops = {
+ 	.is_attach_deferred	= intel_iommu_is_attach_deferred,
+ 	.def_domain_type	= device_def_domain_type,
+ 	.page_response		= intel_iommu_page_response,
+-	.default_domain_ops = &(const struct iommu_domain_ops) {
+-		.attach_dev		= intel_iommu_attach_device,
+-		.set_dev_pasid		= intel_iommu_set_dev_pasid,
+-		.map_pages		= intel_iommu_map_pages,
+-		.unmap_pages		= intel_iommu_unmap_pages,
+-		.iotlb_sync_map		= intel_iommu_iotlb_sync_map,
+-		.flush_iotlb_all        = intel_flush_iotlb_all,
+-		.iotlb_sync		= intel_iommu_tlb_sync,
+-		.iova_to_phys		= intel_iommu_iova_to_phys,
+-		.free			= intel_iommu_domain_free,
+-		.enforce_cache_coherency = intel_iommu_enforce_cache_coherency,
+-	}
+ };
+ 
+ static void quirk_iommu_igfx(struct pci_dev *dev)
+diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
+index 61f42802fe9e95..c699ed8810f23c 100644
+--- a/drivers/iommu/intel/iommu.h
++++ b/drivers/iommu/intel/iommu.h
+@@ -1381,6 +1381,18 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
+ 					 u8 devfn, int alloc);
+ 
+ extern const struct iommu_ops intel_iommu_ops;
++extern const struct iommu_domain_ops intel_fs_paging_domain_ops;
++extern const struct iommu_domain_ops intel_ss_paging_domain_ops;
++
++static inline bool intel_domain_is_fs_paging(struct dmar_domain *domain)
++{
++	return domain->domain.ops == &intel_fs_paging_domain_ops;
++}
++
++static inline bool intel_domain_is_ss_paging(struct dmar_domain *domain)
++{
++	return domain->domain.ops == &intel_ss_paging_domain_ops;
++}
+ 
+ #ifdef CONFIG_INTEL_IOMMU
+ extern int intel_iommu_sm;
+diff --git a/drivers/iommu/intel/nested.c b/drivers/iommu/intel/nested.c
+index fc312f649f9ef0..1b6ad9c900a5ad 100644
+--- a/drivers/iommu/intel/nested.c
++++ b/drivers/iommu/intel/nested.c
+@@ -216,8 +216,7 @@ intel_iommu_domain_alloc_nested(struct device *dev, struct iommu_domain *parent,
+ 	/* Must be nested domain */
+ 	if (user_data->type != IOMMU_HWPT_DATA_VTD_S1)
+ 		return ERR_PTR(-EOPNOTSUPP);
+-	if (parent->ops != intel_iommu_ops.default_domain_ops ||
+-	    !s2_domain->nested_parent)
++	if (!intel_domain_is_ss_paging(s2_domain) || !s2_domain->nested_parent)
+ 		return ERR_PTR(-EINVAL);
+ 
+ 	ret = iommu_copy_struct_from_user(&vtd, user_data,
+@@ -229,7 +228,6 @@ intel_iommu_domain_alloc_nested(struct device *dev, struct iommu_domain *parent,
+ 	if (!domain)
+ 		return ERR_PTR(-ENOMEM);
+ 
+-	domain->use_first_level = true;
+ 	domain->s2_domain = s2_domain;
+ 	domain->s1_cfg = vtd;
+ 	domain->domain.ops = &intel_nested_domain_ops;
+diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
+index f3da596410b5e5..3994521f6ea488 100644
+--- a/drivers/iommu/intel/svm.c
++++ b/drivers/iommu/intel/svm.c
+@@ -214,7 +214,6 @@ struct iommu_domain *intel_svm_domain_alloc(struct device *dev,
+ 		return ERR_PTR(-ENOMEM);
+ 
+ 	domain->domain.ops = &intel_svm_domain_ops;
+-	domain->use_first_level = true;
+ 	INIT_LIST_HEAD(&domain->dev_pasids);
+ 	INIT_LIST_HEAD(&domain->cache_tags);
+ 	spin_lock_init(&domain->cache_lock);
+diff --git a/drivers/irqchip/irq-mvebu-gicp.c b/drivers/irqchip/irq-mvebu-gicp.c
+index 54833717f8a70f..667bde3c651ff2 100644
+--- a/drivers/irqchip/irq-mvebu-gicp.c
++++ b/drivers/irqchip/irq-mvebu-gicp.c
+@@ -238,7 +238,7 @@ static int mvebu_gicp_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	base = ioremap(gicp->res->start, resource_size(gicp->res));
+-	if (IS_ERR(base)) {
++	if (!base) {
+ 		dev_err(&pdev->dev, "ioremap() failed. Unable to clear pending interrupts.\n");
+ 	} else {
+ 		for (i = 0; i < 64; i++)
+diff --git a/drivers/md/md.c b/drivers/md/md.c
+index 3f355bb85797f8..0f41573fa9f5ec 100644
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -1406,7 +1406,7 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *freshest, stru
+ 		else {
+ 			if (sb->events_hi == sb->cp_events_hi &&
+ 				sb->events_lo == sb->cp_events_lo) {
+-				mddev->resync_offset = sb->resync_offset;
++				mddev->resync_offset = sb->recovery_cp;
+ 			} else
+ 				mddev->resync_offset = 0;
+ 		}
+@@ -1534,13 +1534,13 @@ static void super_90_sync(struct mddev *mddev, struct md_rdev *rdev)
+ 	mddev->minor_version = sb->minor_version;
+ 	if (mddev->in_sync)
+ 	{
+-		sb->resync_offset = mddev->resync_offset;
++		sb->recovery_cp = mddev->resync_offset;
+ 		sb->cp_events_hi = (mddev->events>>32);
+ 		sb->cp_events_lo = (u32)mddev->events;
+ 		if (mddev->resync_offset == MaxSector)
+ 			sb->state = (1<< MD_SB_CLEAN);
+ 	} else
+-		sb->resync_offset = 0;
++		sb->recovery_cp = 0;
+ 
+ 	sb->layout = mddev->layout;
+ 	sb->chunk_size = mddev->chunk_sectors << 9;
+diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
+index 84ab4a83cbd686..db94d14a3807f5 100644
+--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
++++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
+@@ -1377,14 +1377,24 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
+ 	if (ret)
+ 		return ret;
+ 
++	/*
++	 * Read setup timing depends on the operation done on the NAND:
++	 *
++	 * NRD_SETUP = max(tAR, tCLR)
++	 */
++	timeps = max(conf->timings.sdr.tAR_min, conf->timings.sdr.tCLR_min);
++	ncycles = DIV_ROUND_UP(timeps, mckperiodps);
++	totalcycles += ncycles;
++	ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NRD_SHIFT, ncycles);
++	if (ret)
++		return ret;
++
+ 	/*
+ 	 * The read cycle timing is directly matching tRC, but is also
+ 	 * dependent on the setup and hold timings we calculated earlier,
+ 	 * which gives:
+ 	 *
+-	 * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
+-	 *
+-	 * NRD_SETUP is always 0.
++	 * NRD_CYCLE = max(tRC, NRD_SETUP + NRD_PULSE + NRD_HOLD)
+ 	 */
+ 	ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
+ 	ncycles = max(totalcycles, ncycles);
+diff --git a/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c b/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c
+index c23b537948d5e6..1a285cd8fad62a 100644
+--- a/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c
++++ b/drivers/mtd/nand/raw/nuvoton-ma35d1-nand-controller.c
+@@ -935,10 +935,10 @@ static void ma35_chips_cleanup(struct ma35_nand_info *nand)
+ 
+ static int ma35_nand_chips_init(struct device *dev, struct ma35_nand_info *nand)
+ {
+-	struct device_node *np = dev->of_node, *nand_np;
++	struct device_node *np = dev->of_node;
+ 	int ret;
+ 
+-	for_each_child_of_node(np, nand_np) {
++	for_each_child_of_node_scoped(np, nand_np) {
+ 		ret = ma35_nand_chip_init(dev, nand, nand_np);
+ 		if (ret) {
+ 			ma35_chips_cleanup(nand);
+diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+index a960403081f110..d957327fb4fa04 100644
+--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c
++++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+@@ -272,6 +272,7 @@ struct stm32_fmc2_nfc {
+ 	struct sg_table dma_data_sg;
+ 	struct sg_table dma_ecc_sg;
+ 	u8 *ecc_buf;
++	dma_addr_t dma_ecc_addr;
+ 	int dma_ecc_len;
+ 	u32 tx_dma_max_burst;
+ 	u32 rx_dma_max_burst;
+@@ -902,17 +903,10 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
+ 
+ 	if (!write_data && !raw) {
+ 		/* Configure DMA ECC status */
+-		p = nfc->ecc_buf;
+ 		for_each_sg(nfc->dma_ecc_sg.sgl, sg, eccsteps, s) {
+-			sg_set_buf(sg, p, nfc->dma_ecc_len);
+-			p += nfc->dma_ecc_len;
+-		}
+-
+-		ret = dma_map_sg(nfc->dev, nfc->dma_ecc_sg.sgl,
+-				 eccsteps, dma_data_dir);
+-		if (!ret) {
+-			ret = -EIO;
+-			goto err_unmap_data;
++			sg_dma_address(sg) = nfc->dma_ecc_addr +
++					     s * nfc->dma_ecc_len;
++			sg_dma_len(sg) = nfc->dma_ecc_len;
+ 		}
+ 
+ 		desc_ecc = dmaengine_prep_slave_sg(nfc->dma_ecc_ch,
+@@ -921,7 +915,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
+ 						   DMA_PREP_INTERRUPT);
+ 		if (!desc_ecc) {
+ 			ret = -ENOMEM;
+-			goto err_unmap_ecc;
++			goto err_unmap_data;
+ 		}
+ 
+ 		reinit_completion(&nfc->dma_ecc_complete);
+@@ -929,7 +923,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
+ 		desc_ecc->callback_param = &nfc->dma_ecc_complete;
+ 		ret = dma_submit_error(dmaengine_submit(desc_ecc));
+ 		if (ret)
+-			goto err_unmap_ecc;
++			goto err_unmap_data;
+ 
+ 		dma_async_issue_pending(nfc->dma_ecc_ch);
+ 	}
+@@ -949,7 +943,7 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
+ 		if (!write_data && !raw)
+ 			dmaengine_terminate_all(nfc->dma_ecc_ch);
+ 		ret = -ETIMEDOUT;
+-		goto err_unmap_ecc;
++		goto err_unmap_data;
+ 	}
+ 
+ 	/* Wait DMA data transfer completion */
+@@ -969,11 +963,6 @@ static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf,
+ 		}
+ 	}
+ 
+-err_unmap_ecc:
+-	if (!write_data && !raw)
+-		dma_unmap_sg(nfc->dev, nfc->dma_ecc_sg.sgl,
+-			     eccsteps, dma_data_dir);
+-
+ err_unmap_data:
+ 	dma_unmap_sg(nfc->dev, nfc->dma_data_sg.sgl, eccsteps, dma_data_dir);
+ 
+@@ -996,9 +985,21 @@ static int stm32_fmc2_nfc_seq_write(struct nand_chip *chip, const u8 *buf,
+ 
+ 	/* Write oob */
+ 	if (oob_required) {
+-		ret = nand_change_write_column_op(chip, mtd->writesize,
+-						  chip->oob_poi, mtd->oobsize,
+-						  false);
++		unsigned int offset_in_page = mtd->writesize;
++		const void *buf = chip->oob_poi;
++		unsigned int len = mtd->oobsize;
++
++		if (!raw) {
++			struct mtd_oob_region oob_free;
++
++			mtd_ooblayout_free(mtd, 0, &oob_free);
++			offset_in_page += oob_free.offset;
++			buf += oob_free.offset;
++			len = oob_free.length;
++		}
++
++		ret = nand_change_write_column_op(chip, offset_in_page,
++						  buf, len, false);
+ 		if (ret)
+ 			return ret;
+ 	}
+@@ -1610,7 +1611,8 @@ static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc)
+ 		return ret;
+ 
+ 	/* Allocate a buffer to store ECC status registers */
+-	nfc->ecc_buf = devm_kzalloc(nfc->dev, FMC2_MAX_ECC_BUF_LEN, GFP_KERNEL);
++	nfc->ecc_buf = dmam_alloc_coherent(nfc->dev, FMC2_MAX_ECC_BUF_LEN,
++					   &nfc->dma_ecc_addr, GFP_KERNEL);
+ 	if (!nfc->ecc_buf)
+ 		return -ENOMEM;
+ 
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index b90f15c986a317..aa6fb862451aa4 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -20,7 +20,7 @@
+ #include <linux/spi/spi.h>
+ #include <linux/spi/spi-mem.h>
+ 
+-static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
++int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val)
+ {
+ 	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(reg,
+ 						      spinand->scratchbuf);
+@@ -1253,8 +1253,19 @@ static int spinand_id_detect(struct spinand_device *spinand)
+ 
+ static int spinand_manufacturer_init(struct spinand_device *spinand)
+ {
+-	if (spinand->manufacturer->ops->init)
+-		return spinand->manufacturer->ops->init(spinand);
++	int ret;
++
++	if (spinand->manufacturer->ops->init) {
++		ret = spinand->manufacturer->ops->init(spinand);
++		if (ret)
++			return ret;
++	}
++
++	if (spinand->configure_chip) {
++		ret = spinand->configure_chip(spinand);
++		if (ret)
++			return ret;
++	}
+ 
+ 	return 0;
+ }
+@@ -1349,6 +1360,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
+ 		spinand->flags = table[i].flags;
+ 		spinand->id.len = 1 + table[i].devid.len;
+ 		spinand->select_target = table[i].select_target;
++		spinand->configure_chip = table[i].configure_chip;
+ 		spinand->set_cont_read = table[i].set_cont_read;
+ 		spinand->fact_otp = &table[i].fact_otp;
+ 		spinand->user_otp = &table[i].user_otp;
+diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
+index b7a28f001a387b..116ac17591a86b 100644
+--- a/drivers/mtd/nand/spi/winbond.c
++++ b/drivers/mtd/nand/spi/winbond.c
+@@ -18,6 +18,9 @@
+ 
+ #define W25N04KV_STATUS_ECC_5_8_BITFLIPS	(3 << 4)
+ 
++#define W25N0XJW_SR4			0xD0
++#define W25N0XJW_SR4_HS			BIT(2)
++
+ /*
+  * "X2" in the core is equivalent to "dual output" in the datasheets,
+  * "X4" in the core is equivalent to "quad output" in the datasheets.
+@@ -42,10 +45,12 @@ static SPINAND_OP_VARIANTS(update_cache_octal_variants,
+ static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_variants,
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
++		SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 104 * HZ_PER_MHZ),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
++		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 104 * HZ_PER_MHZ),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
+ 		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
+@@ -157,6 +162,36 @@ static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
+ 	.free = w25n02kv_ooblayout_free,
+ };
+ 
++static int w25n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *region)
++{
++	if (section > 3)
++		return -ERANGE;
++
++	region->offset = (16 * section) + 12;
++	region->length = 4;
++
++	return 0;
++}
++
++static int w25n01jw_ooblayout_free(struct mtd_info *mtd, int section,
++				   struct mtd_oob_region *region)
++{
++	if (section > 3)
++		return -ERANGE;
++
++	region->offset = (16 * section);
++	region->length = 12;
++
++	/* Extract BBM */
++	if (!section) {
++		region->offset += 2;
++		region->length -= 2;
++	}
++
++	return 0;
++}
++
+ static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
+ 				  struct mtd_oob_region *region)
+ {
+@@ -187,6 +222,11 @@ static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section,
+ 	return 0;
+ }
+ 
++static const struct mtd_ooblayout_ops w25n01jw_ooblayout = {
++	.ecc = w25n01jw_ooblayout_ecc,
++	.free = w25n01jw_ooblayout_free,
++};
++
+ static const struct mtd_ooblayout_ops w35n01jw_ooblayout = {
+ 	.ecc = w35n01jw_ooblayout_ecc,
+ 	.free = w35n01jw_ooblayout_free,
+@@ -230,6 +270,40 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
+ 	return -EINVAL;
+ }
+ 
++static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
++{
++	const struct spi_mem_op *op;
++	bool hs;
++	u8 sr4;
++	int ret;
++
++	op = spinand->op_templates.read_cache;
++	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
++		hs = false;
++	else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 &&
++		 op->dummy.buswidth == 1 && op->data.buswidth == 1)
++		hs = false;
++	else if (!op->max_freq)
++		hs = true;
++	else
++		hs = false;
++
++	ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4);
++	if (ret)
++		return ret;
++
++	if (hs)
++		sr4 |= W25N0XJW_SR4_HS;
++	else
++		sr4 &= ~W25N0XJW_SR4_HS;
++
++	ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
+ static const struct spinand_info winbond_spinand_table[] = {
+ 	/* 512M-bit densities */
+ 	SPINAND_INFO("W25N512GW", /* 1.8V */
+@@ -268,7 +342,8 @@ static const struct spinand_info winbond_spinand_table[] = {
+ 					      &write_cache_variants,
+ 					      &update_cache_variants),
+ 		     0,
+-		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
++		     SPINAND_ECCINFO(&w25n01jw_ooblayout, NULL),
++		     SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
+ 	SPINAND_INFO("W25N01KV", /* 3.3V */
+ 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
+ 		     NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1),
+@@ -324,7 +399,8 @@ static const struct spinand_info winbond_spinand_table[] = {
+ 					      &write_cache_variants,
+ 					      &update_cache_variants),
+ 		     0,
+-		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
++		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
++		     SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
+ 	SPINAND_INFO("W25N02KV", /* 3.3V */
+ 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
+ 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
+index 3f2e378199abba..5abe4af61655cd 100644
+--- a/drivers/net/can/xilinx_can.c
++++ b/drivers/net/can/xilinx_can.c
+@@ -690,14 +690,6 @@ static void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb,
+ 		dlc |= XCAN_DLCR_EDL_MASK;
+ 	}
+ 
+-	if (!(priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) &&
+-	    (priv->devtype.flags & XCAN_FLAG_TXFEMP))
+-		can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max, 0);
+-	else
+-		can_put_echo_skb(skb, ndev, 0, 0);
+-
+-	priv->tx_head++;
+-
+ 	priv->write_reg(priv, XCAN_FRAME_ID_OFFSET(frame_offset), id);
+ 	/* If the CAN frame is RTR frame this write triggers transmission
+ 	 * (not on CAN FD)
+@@ -730,6 +722,14 @@ static void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb,
+ 					data[1]);
+ 		}
+ 	}
++
++	if (!(priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) &&
++	    (priv->devtype.flags & XCAN_FLAG_TXFEMP))
++		can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max, 0);
++	else
++		can_put_echo_skb(skb, ndev, 0, 0);
++
++	priv->tx_head++;
+ }
+ 
+ /**
+diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
+index d15d912690c40e..073d20241a4c9c 100644
+--- a/drivers/net/dsa/b53/b53_common.c
++++ b/drivers/net/dsa/b53/b53_common.c
+@@ -1229,9 +1229,15 @@ static int b53_setup(struct dsa_switch *ds)
+ 	 */
+ 	ds->untag_vlan_aware_bridge_pvid = true;
+ 
+-	/* Ageing time is set in seconds */
+-	ds->ageing_time_min = 1 * 1000;
+-	ds->ageing_time_max = AGE_TIME_MAX * 1000;
++	if (dev->chip_id == BCM53101_DEVICE_ID) {
++		/* BCM53101 uses 0.5 second increments */
++		ds->ageing_time_min = 1 * 500;
++		ds->ageing_time_max = AGE_TIME_MAX * 500;
++	} else {
++		/* Everything else uses 1 second increments */
++		ds->ageing_time_min = 1 * 1000;
++		ds->ageing_time_max = AGE_TIME_MAX * 1000;
++	}
+ 
+ 	ret = b53_reset_switch(dev);
+ 	if (ret) {
+@@ -2448,7 +2454,10 @@ int b53_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
+ 	else
+ 		reg = B53_AGING_TIME_CONTROL;
+ 
+-	atc = DIV_ROUND_CLOSEST(msecs, 1000);
++	if (dev->chip_id == BCM53101_DEVICE_ID)
++		atc = DIV_ROUND_CLOSEST(msecs, 500);
++	else
++		atc = DIV_ROUND_CLOSEST(msecs, 1000);
+ 
+ 	if (!is5325(dev) && !is5365(dev))
+ 		atc |= AGE_CHANGE;
+diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
+index 651b73163b6ee9..5f15f42070c539 100644
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -2358,7 +2358,8 @@ static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev)
+ 		 */
+ 		phy_dev = of_phy_find_device(fep->phy_node);
+ 		phy_reset_after_clk_enable(phy_dev);
+-		put_device(&phy_dev->mdio.dev);
++		if (phy_dev)
++			put_device(&phy_dev->mdio.dev);
+ 	}
+ }
+ 
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
+index f1c9e575703eaa..26dcdceae741e4 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
+@@ -4182,7 +4182,7 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
+ 		irq_num = pf->msix_entries[base + vector].vector;
+ 		irq_set_affinity_notifier(irq_num, NULL);
+ 		irq_update_affinity_hint(irq_num, NULL);
+-		free_irq(irq_num, &vsi->q_vectors[vector]);
++		free_irq(irq_num, vsi->q_vectors[vector]);
+ 	}
+ 	return err;
+ }
+diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
+index ca6ccbc139548b..6412c84e2d17db 100644
+--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
++++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
+@@ -2081,11 +2081,8 @@ static void igb_diag_test(struct net_device *netdev,
+ 	} else {
+ 		dev_info(&adapter->pdev->dev, "online testing starting\n");
+ 
+-		/* PHY is powered down when interface is down */
+-		if (if_running && igb_link_test(adapter, &data[TEST_LINK]))
++		if (igb_link_test(adapter, &data[TEST_LINK]))
+ 			eth_test->flags |= ETH_TEST_FL_FAILED;
+-		else
+-			data[TEST_LINK] = 0;
+ 
+ 		/* Online tests aren't run; pass by default */
+ 		data[TEST_REG] = 0;
+diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
+index b76a154e635e00..d87438bef6fba5 100644
+--- a/drivers/net/ethernet/intel/igb/igb_main.c
++++ b/drivers/net/ethernet/intel/igb/igb_main.c
+@@ -4451,8 +4451,7 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
+ 	if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ 		xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+ 	res = xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev,
+-			       rx_ring->queue_index,
+-			       rx_ring->q_vector->napi.napi_id);
++			       rx_ring->queue_index, 0);
+ 	if (res < 0) {
+ 		dev_err(dev, "Failed to register xdp_rxq index %u\n",
+ 			rx_ring->queue_index);
+diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+index f436d7cf565a14..1a9cc8206430b2 100644
+--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
++++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+@@ -691,7 +691,7 @@ static void icssg_prueth_hsr_fdb_add_del(struct prueth_emac *emac,
+ 
+ static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
+ {
+-	struct net_device *real_dev;
++	struct net_device *real_dev, *port_dev;
+ 	struct prueth_emac *emac;
+ 	u8 vlan_id, i;
+ 
+@@ -700,11 +700,15 @@ static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
+ 
+ 	if (is_hsr_master(real_dev)) {
+ 		for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
+-			emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
+-			if (!emac)
++			port_dev = hsr_get_port_ndev(real_dev, i);
++			emac = netdev_priv(port_dev);
++			if (!emac) {
++				dev_put(port_dev);
+ 				return -EINVAL;
++			}
+ 			icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
+ 						     true);
++			dev_put(port_dev);
+ 		}
+ 	} else {
+ 		emac = netdev_priv(real_dev);
+@@ -716,7 +720,7 @@ static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
+ 
+ static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)
+ {
+-	struct net_device *real_dev;
++	struct net_device *real_dev, *port_dev;
+ 	struct prueth_emac *emac;
+ 	u8 vlan_id, i;
+ 
+@@ -725,11 +729,15 @@ static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)
+ 
+ 	if (is_hsr_master(real_dev)) {
+ 		for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
+-			emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
+-			if (!emac)
++			port_dev = hsr_get_port_ndev(real_dev, i);
++			emac = netdev_priv(port_dev);
++			if (!emac) {
++				dev_put(port_dev);
+ 				return -EINVAL;
++			}
+ 			icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
+ 						     false);
++			dev_put(port_dev);
+ 		}
+ 	} else {
+ 		emac = netdev_priv(real_dev);
+diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+index f0823aa1ede607..bb1dcdf5fd0d58 100644
+--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
++++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+@@ -2071,10 +2071,6 @@ static void wx_setup_mrqc(struct wx *wx)
+ {
+ 	u32 rss_field = 0;
+ 
+-	/* VT, and RSS do not coexist at the same time */
+-	if (test_bit(WX_FLAG_VMDQ_ENABLED, wx->flags))
+-		return;
+-
+ 	/* Disable indicating checksum in descriptor, enables RSS hash */
+ 	wr32m(wx, WX_PSR_CTL, WX_PSR_CTL_PCSD, WX_PSR_CTL_PCSD);
+ 
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 01329fe7451a12..0eca96eeed58ab 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -4286,6 +4286,7 @@ static int macsec_newlink(struct net_device *dev,
+ 	if (err < 0)
+ 		goto del_dev;
+ 
++	netdev_update_features(dev);
+ 	netif_stacked_transfer_operstate(real_dev, dev);
+ 	linkwatch_fire_event(dev);
+ 
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index 13df28445f0201..c02da57a4da5e3 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -1065,23 +1065,19 @@ EXPORT_SYMBOL_GPL(phy_inband_caps);
+  */
+ int phy_config_inband(struct phy_device *phydev, unsigned int modes)
+ {
+-	int err;
++	lockdep_assert_held(&phydev->lock);
+ 
+ 	if (!!(modes & LINK_INBAND_DISABLE) +
+ 	    !!(modes & LINK_INBAND_ENABLE) +
+ 	    !!(modes & LINK_INBAND_BYPASS) != 1)
+ 		return -EINVAL;
+ 
+-	mutex_lock(&phydev->lock);
+ 	if (!phydev->drv)
+-		err = -EIO;
++		return -EIO;
+ 	else if (!phydev->drv->config_inband)
+-		err = -EOPNOTSUPP;
+-	else
+-		err = phydev->drv->config_inband(phydev, modes);
+-	mutex_unlock(&phydev->lock);
++		return -EOPNOTSUPP;
+ 
+-	return err;
++	return phydev->drv->config_inband(phydev, modes);
+ }
+ EXPORT_SYMBOL(phy_config_inband);
+ 
+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
+index 0faa3d97e06b94..229a503d601eed 100644
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -67,6 +67,8 @@ struct phylink {
+ 	struct timer_list link_poll;
+ 
+ 	struct mutex state_mutex;
++	/* Serialize updates to pl->phydev with phylink_resolve() */
++	struct mutex phydev_mutex;
+ 	struct phylink_link_state phy_state;
+ 	unsigned int phy_ib_mode;
+ 	struct work_struct resolve;
+@@ -1409,6 +1411,7 @@ static void phylink_get_fixed_state(struct phylink *pl,
+ static void phylink_mac_initial_config(struct phylink *pl, bool force_restart)
+ {
+ 	struct phylink_link_state link_state;
++	struct phy_device *phy = pl->phydev;
+ 
+ 	switch (pl->req_link_an_mode) {
+ 	case MLO_AN_PHY:
+@@ -1432,7 +1435,11 @@ static void phylink_mac_initial_config(struct phylink *pl, bool force_restart)
+ 	link_state.link = false;
+ 
+ 	phylink_apply_manual_flow(pl, &link_state);
++	if (phy)
++		mutex_lock(&phy->lock);
+ 	phylink_major_config(pl, force_restart, &link_state);
++	if (phy)
++		mutex_unlock(&phy->lock);
+ }
+ 
+ static const char *phylink_pause_to_str(int pause)
+@@ -1568,8 +1575,13 @@ static void phylink_resolve(struct work_struct *w)
+ 	struct phylink_link_state link_state;
+ 	bool mac_config = false;
+ 	bool retrigger = false;
++	struct phy_device *phy;
+ 	bool cur_link_state;
+ 
++	mutex_lock(&pl->phydev_mutex);
++	phy = pl->phydev;
++	if (phy)
++		mutex_lock(&phy->lock);
+ 	mutex_lock(&pl->state_mutex);
+ 	cur_link_state = phylink_link_is_up(pl);
+ 
+@@ -1603,11 +1615,11 @@ static void phylink_resolve(struct work_struct *w)
+ 		/* If we have a phy, the "up" state is the union of both the
+ 		 * PHY and the MAC
+ 		 */
+-		if (pl->phydev)
++		if (phy)
+ 			link_state.link &= pl->phy_state.link;
+ 
+ 		/* Only update if the PHY link is up */
+-		if (pl->phydev && pl->phy_state.link) {
++		if (phy && pl->phy_state.link) {
+ 			/* If the interface has changed, force a link down
+ 			 * event if the link isn't already down, and re-resolve.
+ 			 */
+@@ -1671,6 +1683,9 @@ static void phylink_resolve(struct work_struct *w)
+ 		queue_work(system_power_efficient_wq, &pl->resolve);
+ 	}
+ 	mutex_unlock(&pl->state_mutex);
++	if (phy)
++		mutex_unlock(&phy->lock);
++	mutex_unlock(&pl->phydev_mutex);
+ }
+ 
+ static void phylink_run_resolve(struct phylink *pl)
+@@ -1806,6 +1821,7 @@ struct phylink *phylink_create(struct phylink_config *config,
+ 	if (!pl)
+ 		return ERR_PTR(-ENOMEM);
+ 
++	mutex_init(&pl->phydev_mutex);
+ 	mutex_init(&pl->state_mutex);
+ 	INIT_WORK(&pl->resolve, phylink_resolve);
+ 
+@@ -2066,6 +2082,7 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
+ 		     dev_name(&phy->mdio.dev), phy->drv->name, irq_str);
+ 	kfree(irq_str);
+ 
++	mutex_lock(&pl->phydev_mutex);
+ 	mutex_lock(&phy->lock);
+ 	mutex_lock(&pl->state_mutex);
+ 	pl->phydev = phy;
+@@ -2111,6 +2128,7 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
+ 
+ 	mutex_unlock(&pl->state_mutex);
+ 	mutex_unlock(&phy->lock);
++	mutex_unlock(&pl->phydev_mutex);
+ 
+ 	phylink_dbg(pl,
+ 		    "phy: %s setting supported %*pb advertising %*pb\n",
+@@ -2289,6 +2307,7 @@ void phylink_disconnect_phy(struct phylink *pl)
+ 
+ 	ASSERT_RTNL();
+ 
++	mutex_lock(&pl->phydev_mutex);
+ 	phy = pl->phydev;
+ 	if (phy) {
+ 		mutex_lock(&phy->lock);
+@@ -2298,8 +2317,11 @@ void phylink_disconnect_phy(struct phylink *pl)
+ 		pl->mac_tx_clk_stop = false;
+ 		mutex_unlock(&pl->state_mutex);
+ 		mutex_unlock(&phy->lock);
+-		flush_work(&pl->resolve);
++	}
++	mutex_unlock(&pl->phydev_mutex);
+ 
++	if (phy) {
++		flush_work(&pl->resolve);
+ 		phy_disconnect(phy);
+ 	}
+ }
+diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
+index 4bd286296da794..cebdf62ce3db9b 100644
+--- a/drivers/net/wireless/ath/ath12k/core.h
++++ b/drivers/net/wireless/ath/ath12k/core.h
+@@ -116,6 +116,7 @@ static inline u64 ath12k_le32hilo_to_u64(__le32 hi, __le32 lo)
+ enum ath12k_skb_flags {
+ 	ATH12K_SKB_HW_80211_ENCAP = BIT(0),
+ 	ATH12K_SKB_CIPHER_SET = BIT(1),
++	ATH12K_SKB_MLO_STA = BIT(2),
+ };
+ 
+ struct ath12k_skb_cb {
+diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
+index 91f4e3aff74c38..6a0915a0c7aae3 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
++++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
+@@ -3610,7 +3610,6 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar,
+ 				   struct hal_rx_mon_ppdu_info *ppdu_info,
+ 				   u32 uid)
+ {
+-	struct ath12k_sta *ahsta;
+ 	struct ath12k_link_sta *arsta;
+ 	struct ath12k_rx_peer_stats *rx_stats = NULL;
+ 	struct hal_rx_user_status *user_stats = &ppdu_info->userstats[uid];
+@@ -3628,8 +3627,13 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar,
+ 		return;
+ 	}
+ 
+-	ahsta = ath12k_sta_to_ahsta(peer->sta);
+-	arsta = &ahsta->deflink;
++	arsta = ath12k_peer_get_link_sta(ar->ab, peer);
++	if (!arsta) {
++		ath12k_warn(ar->ab, "link sta not found on peer %pM id %d\n",
++			    peer->addr, peer->peer_id);
++		return;
++	}
++
+ 	arsta->rssi_comb = ppdu_info->rssi_comb;
+ 	ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb);
+ 	rx_stats = arsta->rx_stats;
+@@ -3742,7 +3746,6 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget,
+ 	struct dp_srng *mon_dst_ring;
+ 	struct hal_srng *srng;
+ 	struct dp_rxdma_mon_ring *buf_ring;
+-	struct ath12k_sta *ahsta = NULL;
+ 	struct ath12k_link_sta *arsta;
+ 	struct ath12k_peer *peer;
+ 	struct sk_buff_head skb_list;
+@@ -3868,8 +3871,15 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget,
+ 		}
+ 
+ 		if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) {
+-			ahsta = ath12k_sta_to_ahsta(peer->sta);
+-			arsta = &ahsta->deflink;
++			arsta = ath12k_peer_get_link_sta(ar->ab, peer);
++			if (!arsta) {
++				ath12k_warn(ar->ab, "link sta not found on peer %pM id %d\n",
++					    peer->addr, peer->peer_id);
++				spin_unlock_bh(&ab->base_lock);
++				rcu_read_unlock();
++				dev_kfree_skb_any(skb);
++				continue;
++			}
+ 			ath12k_dp_mon_rx_update_peer_su_stats(ar, arsta,
+ 							      ppdu_info);
+ 		} else if ((ppdu_info->fc_valid) &&
+diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
+index bd95dc88f9b21f..e9137ffeb5ab48 100644
+--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
+@@ -1418,8 +1418,6 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar,
+ {
+ 	struct ath12k_base *ab = ar->ab;
+ 	struct ath12k_peer *peer;
+-	struct ieee80211_sta *sta;
+-	struct ath12k_sta *ahsta;
+ 	struct ath12k_link_sta *arsta;
+ 	struct htt_ppdu_stats_user_rate *user_rate;
+ 	struct ath12k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats;
+@@ -1500,9 +1498,12 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar,
+ 		return;
+ 	}
+ 
+-	sta = peer->sta;
+-	ahsta = ath12k_sta_to_ahsta(sta);
+-	arsta = &ahsta->deflink;
++	arsta = ath12k_peer_get_link_sta(ab, peer);
++	if (!arsta) {
++		spin_unlock_bh(&ab->base_lock);
++		rcu_read_unlock();
++		return;
++	}
+ 
+ 	memset(&arsta->txrate, 0, sizeof(arsta->txrate));
+ 
+diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
+index ec77ad498b33a2..6791ae1d64e50f 100644
+--- a/drivers/net/wireless/ath/ath12k/hw.c
++++ b/drivers/net/wireless/ath/ath12k/hw.c
+@@ -14,6 +14,7 @@
+ #include "hw.h"
+ #include "mhi.h"
+ #include "dp_rx.h"
++#include "peer.h"
+ 
+ static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
+ 					     0x90, 0xd6, 0x02, 0x42,
+@@ -49,6 +50,12 @@ static bool ath12k_dp_srng_is_comp_ring_qcn9274(int ring_num)
+ 	return false;
+ }
+ 
++static bool ath12k_is_frame_link_agnostic_qcn9274(struct ath12k_link_vif *arvif,
++						  struct ieee80211_mgmt *mgmt)
++{
++	return ieee80211_is_action(mgmt->frame_control);
++}
++
+ static int ath12k_hw_mac_id_to_pdev_id_wcn7850(const struct ath12k_hw_params *hw,
+ 					       int mac_id)
+ {
+@@ -74,6 +81,52 @@ static bool ath12k_dp_srng_is_comp_ring_wcn7850(int ring_num)
+ 	return false;
+ }
+ 
++static bool ath12k_is_addba_resp_action_code(struct ieee80211_mgmt *mgmt)
++{
++	if (!ieee80211_is_action(mgmt->frame_control))
++		return false;
++
++	if (mgmt->u.action.category != WLAN_CATEGORY_BACK)
++		return false;
++
++	if (mgmt->u.action.u.addba_resp.action_code != WLAN_ACTION_ADDBA_RESP)
++		return false;
++
++	return true;
++}
++
++static bool ath12k_is_frame_link_agnostic_wcn7850(struct ath12k_link_vif *arvif,
++						  struct ieee80211_mgmt *mgmt)
++{
++	struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
++	struct ath12k_hw *ah = ath12k_ar_to_ah(arvif->ar);
++	struct ath12k_base *ab = arvif->ar->ab;
++	__le16 fc = mgmt->frame_control;
++
++	spin_lock_bh(&ab->base_lock);
++	if (!ath12k_peer_find_by_addr(ab, mgmt->da) &&
++	    !ath12k_peer_ml_find(ah, mgmt->da)) {
++		spin_unlock_bh(&ab->base_lock);
++		return false;
++	}
++	spin_unlock_bh(&ab->base_lock);
++
++	if (vif->type == NL80211_IFTYPE_STATION)
++		return arvif->is_up &&
++		       (vif->valid_links == vif->active_links) &&
++		       !ieee80211_is_probe_req(fc) &&
++		       !ieee80211_is_auth(fc) &&
++		       !ieee80211_is_deauth(fc) &&
++		       !ath12k_is_addba_resp_action_code(mgmt);
++
++	if (vif->type == NL80211_IFTYPE_AP)
++		return !(ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) ||
++			 ieee80211_is_assoc_resp(fc) || ieee80211_is_reassoc_resp(fc) ||
++			 ath12k_is_addba_resp_action_code(mgmt));
++
++	return false;
++}
++
+ static const struct ath12k_hw_ops qcn9274_ops = {
+ 	.get_hw_mac_from_pdev_id = ath12k_hw_qcn9274_mac_from_pdev_id,
+ 	.mac_id_to_pdev_id = ath12k_hw_mac_id_to_pdev_id_qcn9274,
+@@ -81,6 +134,7 @@ static const struct ath12k_hw_ops qcn9274_ops = {
+ 	.rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_qcn9274,
+ 	.get_ring_selector = ath12k_hw_get_ring_selector_qcn9274,
+ 	.dp_srng_is_tx_comp_ring = ath12k_dp_srng_is_comp_ring_qcn9274,
++	.is_frame_link_agnostic = ath12k_is_frame_link_agnostic_qcn9274,
+ };
+ 
+ static const struct ath12k_hw_ops wcn7850_ops = {
+@@ -90,6 +144,7 @@ static const struct ath12k_hw_ops wcn7850_ops = {
+ 	.rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_wcn7850,
+ 	.get_ring_selector = ath12k_hw_get_ring_selector_wcn7850,
+ 	.dp_srng_is_tx_comp_ring = ath12k_dp_srng_is_comp_ring_wcn7850,
++	.is_frame_link_agnostic = ath12k_is_frame_link_agnostic_wcn7850,
+ };
+ 
+ #define ATH12K_TX_RING_MASK_0 0x1
+diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
+index 0a75bc5abfa241..9c69dd5a22afa4 100644
+--- a/drivers/net/wireless/ath/ath12k/hw.h
++++ b/drivers/net/wireless/ath/ath12k/hw.h
+@@ -246,6 +246,8 @@ struct ath12k_hw_ops {
+ 	int (*rxdma_ring_sel_config)(struct ath12k_base *ab);
+ 	u8 (*get_ring_selector)(struct sk_buff *skb);
+ 	bool (*dp_srng_is_tx_comp_ring)(int ring_num);
++	bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif,
++				       struct ieee80211_mgmt *mgmt);
+ };
+ 
+ static inline
+diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
+index a885dd168a372a..708dc3dd4347ad 100644
+--- a/drivers/net/wireless/ath/ath12k/mac.c
++++ b/drivers/net/wireless/ath/ath12k/mac.c
+@@ -3650,12 +3650,68 @@ static int ath12k_mac_fils_discovery(struct ath12k_link_vif *arvif,
+ 	return ret;
+ }
+ 
++static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif)
++{
++	struct ath12k *ar = arvif->ar;
++	struct ieee80211_vif *vif = arvif->ahvif->vif;
++	struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf;
++	enum wmi_sta_powersave_param param;
++	struct ieee80211_bss_conf *info;
++	enum wmi_sta_ps_mode psmode;
++	int ret;
++	int timeout;
++	bool enable_ps;
++
++	lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
++
++	if (vif->type != NL80211_IFTYPE_STATION)
++		return;
++
++	enable_ps = arvif->ahvif->ps;
++	if (enable_ps) {
++		psmode = WMI_STA_PS_MODE_ENABLED;
++		param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
++
++		timeout = conf->dynamic_ps_timeout;
++		if (timeout == 0) {
++			info = ath12k_mac_get_link_bss_conf(arvif);
++			if (!info) {
++				ath12k_warn(ar->ab, "unable to access bss link conf in setup ps for vif %pM link %u\n",
++					    vif->addr, arvif->link_id);
++				return;
++			}
++
++			/* firmware doesn't like 0 */
++			timeout = ieee80211_tu_to_usec(info->beacon_int) / 1000;
++		}
++
++		ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
++						  timeout);
++		if (ret) {
++			ath12k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n",
++				    arvif->vdev_id, ret);
++			return;
++		}
++	} else {
++		psmode = WMI_STA_PS_MODE_DISABLED;
++	}
++
++	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d psmode %s\n",
++		   arvif->vdev_id, psmode ? "enable" : "disable");
++
++	ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode);
++	if (ret)
++		ath12k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n",
++			    psmode, arvif->vdev_id, ret);
++}
++
+ static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw,
+ 					  struct ieee80211_vif *vif,
+ 					  u64 changed)
+ {
+ 	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
+ 	unsigned long links = ahvif->links_map;
++	struct ieee80211_vif_cfg *vif_cfg;
+ 	struct ieee80211_bss_conf *info;
+ 	struct ath12k_link_vif *arvif;
+ 	struct ieee80211_sta *sta;
+@@ -3719,61 +3775,24 @@ static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw,
+ 			}
+ 		}
+ 	}
+-}
+ 
+-static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif)
+-{
+-	struct ath12k *ar = arvif->ar;
+-	struct ieee80211_vif *vif = arvif->ahvif->vif;
+-	struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf;
+-	enum wmi_sta_powersave_param param;
+-	struct ieee80211_bss_conf *info;
+-	enum wmi_sta_ps_mode psmode;
+-	int ret;
+-	int timeout;
+-	bool enable_ps;
++	if (changed & BSS_CHANGED_PS) {
++		links = ahvif->links_map;
++		vif_cfg = &vif->cfg;
+ 
+-	lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
+-
+-	if (vif->type != NL80211_IFTYPE_STATION)
+-		return;
++		for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
++			arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
++			if (!arvif || !arvif->ar)
++				continue;
+ 
+-	enable_ps = arvif->ahvif->ps;
+-	if (enable_ps) {
+-		psmode = WMI_STA_PS_MODE_ENABLED;
+-		param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
++			ar = arvif->ar;
+ 
+-		timeout = conf->dynamic_ps_timeout;
+-		if (timeout == 0) {
+-			info = ath12k_mac_get_link_bss_conf(arvif);
+-			if (!info) {
+-				ath12k_warn(ar->ab, "unable to access bss link conf in setup ps for vif %pM link %u\n",
+-					    vif->addr, arvif->link_id);
+-				return;
++			if (ar->ab->hw_params->supports_sta_ps) {
++				ahvif->ps = vif_cfg->ps;
++				ath12k_mac_vif_setup_ps(arvif);
+ 			}
+-
+-			/* firmware doesn't like 0 */
+-			timeout = ieee80211_tu_to_usec(info->beacon_int) / 1000;
+-		}
+-
+-		ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
+-						  timeout);
+-		if (ret) {
+-			ath12k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n",
+-				    arvif->vdev_id, ret);
+-			return;
+ 		}
+-	} else {
+-		psmode = WMI_STA_PS_MODE_DISABLED;
+ 	}
+-
+-	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d psmode %s\n",
+-		   arvif->vdev_id, psmode ? "enable" : "disable");
+-
+-	ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode);
+-	if (ret)
+-		ath12k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n",
+-			    psmode, arvif->vdev_id, ret);
+ }
+ 
+ static bool ath12k_mac_supports_station_tpc(struct ath12k *ar,
+@@ -3795,7 +3814,6 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
+ {
+ 	struct ath12k_vif *ahvif = arvif->ahvif;
+ 	struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
+-	struct ieee80211_vif_cfg *vif_cfg = &vif->cfg;
+ 	struct cfg80211_chan_def def;
+ 	u32 param_id, param_value;
+ 	enum nl80211_band band;
+@@ -4069,12 +4087,6 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar,
+ 	}
+ 
+ 	ath12k_mac_fils_discovery(arvif, info);
+-
+-	if (changed & BSS_CHANGED_PS &&
+-	    ar->ab->hw_params->supports_sta_ps) {
+-		ahvif->ps = vif_cfg->ps;
+-		ath12k_mac_vif_setup_ps(arvif);
+-	}
+ }
+ 
+ static struct ath12k_vif_cache *ath12k_ahvif_get_link_cache(struct ath12k_vif *ahvif,
+@@ -7673,7 +7685,7 @@ static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arv
+ 
+ 	skb_cb->paddr = paddr;
+ 
+-	ret = ath12k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb);
++	ret = ath12k_wmi_mgmt_send(arvif, buf_id, skb);
+ 	if (ret) {
+ 		ath12k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret);
+ 		goto err_unmap_buf;
+@@ -7985,6 +7997,9 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw,
+ 
+ 		skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP;
+ 	} else if (ieee80211_is_mgmt(hdr->frame_control)) {
++		if (sta && sta->mlo)
++			skb_cb->flags |= ATH12K_SKB_MLO_STA;
++
+ 		ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp);
+ 		if (ret) {
+ 			ath12k_warn(ar->ab, "failed to queue management frame %d\n",
+diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
+index ec7236bbccc0fe..eb7aeff0149038 100644
+--- a/drivers/net/wireless/ath/ath12k/peer.c
++++ b/drivers/net/wireless/ath/ath12k/peer.c
+@@ -8,7 +8,7 @@
+ #include "peer.h"
+ #include "debug.h"
+ 
+-static struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, const u8 *addr)
++struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, const u8 *addr)
+ {
+ 	struct ath12k_ml_peer *ml_peer;
+ 
+diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h
+index f3a5e054d2b556..44afc0b7dd53ea 100644
+--- a/drivers/net/wireless/ath/ath12k/peer.h
++++ b/drivers/net/wireless/ath/ath12k/peer.h
+@@ -91,5 +91,33 @@ struct ath12k_peer *ath12k_peer_find_by_ast(struct ath12k_base *ab, int ast_hash
+ int ath12k_peer_ml_create(struct ath12k_hw *ah, struct ieee80211_sta *sta);
+ int ath12k_peer_ml_delete(struct ath12k_hw *ah, struct ieee80211_sta *sta);
+ int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta);
++struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah,
++					   const u8 *addr);
++static inline
++struct ath12k_link_sta *ath12k_peer_get_link_sta(struct ath12k_base *ab,
++						 struct ath12k_peer *peer)
++{
++	struct ath12k_sta *ahsta;
++	struct ath12k_link_sta *arsta;
++
++	if (!peer->sta)
++		return NULL;
++
++	ahsta = ath12k_sta_to_ahsta(peer->sta);
++	if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) {
++		if (!(ahsta->links_map & BIT(peer->link_id))) {
++			ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n",
++				    peer->addr, peer->peer_id, peer->link_id,
++				    ahsta->links_map);
++			return NULL;
++		}
++		arsta = rcu_dereference(ahsta->link[peer->link_id]);
++		if (!arsta)
++			return NULL;
++	} else {
++		arsta =  &ahsta->deflink;
++	}
++	return arsta;
++}
+ 
+ #endif /* _PEER_H_ */
+diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
+index eac5d48cade663..d740326079e1d7 100644
+--- a/drivers/net/wireless/ath/ath12k/wmi.c
++++ b/drivers/net/wireless/ath/ath12k/wmi.c
+@@ -782,20 +782,46 @@ struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len)
+ 	return skb;
+ }
+ 
+-int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id,
++int ath12k_wmi_mgmt_send(struct ath12k_link_vif *arvif, u32 buf_id,
+ 			 struct sk_buff *frame)
+ {
++	struct ath12k *ar = arvif->ar;
+ 	struct ath12k_wmi_pdev *wmi = ar->wmi;
+ 	struct wmi_mgmt_send_cmd *cmd;
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame);
+-	struct wmi_tlv *frame_tlv;
++	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)frame->data;
++	struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
++	int cmd_len = sizeof(struct ath12k_wmi_mgmt_send_tx_params);
++	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr;
++	struct ath12k_wmi_mlo_mgmt_send_params *ml_params;
++	struct ath12k_base *ab = ar->ab;
++	struct wmi_tlv *frame_tlv, *tlv;
++	struct ath12k_skb_cb *skb_cb;
++	u32 buf_len, buf_len_aligned;
++	u32 vdev_id = arvif->vdev_id;
++	bool link_agnostic = false;
+ 	struct sk_buff *skb;
+-	u32 buf_len;
+ 	int ret, len;
++	void *ptr;
+ 
+ 	buf_len = min_t(int, frame->len, WMI_MGMT_SEND_DOWNLD_LEN);
+ 
+-	len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4);
++	buf_len_aligned = roundup(buf_len, sizeof(u32));
++
++	len = sizeof(*cmd) + sizeof(*frame_tlv) + buf_len_aligned;
++
++	if (ieee80211_vif_is_mld(vif)) {
++		skb_cb = ATH12K_SKB_CB(frame);
++		if ((skb_cb->flags & ATH12K_SKB_MLO_STA) &&
++		    ab->hw_params->hw_ops->is_frame_link_agnostic &&
++		    ab->hw_params->hw_ops->is_frame_link_agnostic(arvif, mgmt)) {
++			len += cmd_len + TLV_HDR_SIZE + sizeof(*ml_params);
++			ath12k_generic_dbg(ATH12K_DBG_MGMT,
++					   "Sending Mgmt Frame fc 0x%0x as link agnostic",
++					   mgmt->frame_control);
++			link_agnostic = true;
++		}
++	}
+ 
+ 	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
+ 	if (!skb)
+@@ -814,10 +840,32 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id,
+ 	cmd->tx_params_valid = 0;
+ 
+ 	frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));
+-	frame_tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, buf_len);
++	frame_tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, buf_len_aligned);
+ 
+ 	memcpy(frame_tlv->value, frame->data, buf_len);
+ 
++	if (!link_agnostic)
++		goto send;
++
++	ptr = skb->data + sizeof(*cmd) + sizeof(*frame_tlv) + buf_len_aligned;
++
++	tlv = ptr;
++
++	/* Tx params not used currently */
++	tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_TX_SEND_PARAMS, cmd_len);
++	ptr += cmd_len;
++
++	tlv = ptr;
++	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, sizeof(*ml_params));
++	ptr += TLV_HDR_SIZE;
++
++	ml_params = ptr;
++	ml_params->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_TX_SEND_PARAMS,
++						       sizeof(*ml_params));
++
++	ml_params->hw_link_id = cpu_to_le32(WMI_MGMT_LINK_AGNOSTIC_ID);
++
++send:
+ 	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID);
+ 	if (ret) {
+ 		ath12k_warn(ar->ab,
+diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
+index 8627154f1680fa..6dbcedcf081759 100644
+--- a/drivers/net/wireless/ath/ath12k/wmi.h
++++ b/drivers/net/wireless/ath/ath12k/wmi.h
+@@ -3963,6 +3963,7 @@ struct wmi_scan_chan_list_cmd {
+ } __packed;
+ 
+ #define WMI_MGMT_SEND_DOWNLD_LEN	64
++#define WMI_MGMT_LINK_AGNOSTIC_ID	0xFFFFFFFF
+ 
+ #define WMI_TX_PARAMS_DWORD0_POWER		GENMASK(7, 0)
+ #define WMI_TX_PARAMS_DWORD0_MCS_MASK		GENMASK(19, 8)
+@@ -3988,7 +3989,18 @@ struct wmi_mgmt_send_cmd {
+ 
+ 	/* This TLV is followed by struct wmi_mgmt_frame */
+ 
+-	/* Followed by struct wmi_mgmt_send_params */
++	/* Followed by struct ath12k_wmi_mlo_mgmt_send_params */
++} __packed;
++
++struct ath12k_wmi_mlo_mgmt_send_params {
++	__le32 tlv_header;
++	__le32 hw_link_id;
++} __packed;
++
++struct ath12k_wmi_mgmt_send_tx_params {
++	__le32 tlv_header;
++	__le32 tx_param_dword0;
++	__le32 tx_param_dword1;
+ } __packed;
+ 
+ struct wmi_sta_powersave_mode_cmd {
+@@ -6183,7 +6195,7 @@ void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
+ int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,
+ 			u32 cmd_id);
+ struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len);
+-int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id,
++int ath12k_wmi_mgmt_send(struct ath12k_link_vif *arvif, u32 buf_id,
+ 			 struct sk_buff *frame);
+ int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id,
+ 			     const u8 *p2p_ie);
+diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+index 4e47ccb43bd86c..edd99d71016cb1 100644
+--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+@@ -124,13 +124,13 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = {
+ 	{IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_mac_cfg)},/* low 5GHz active */
+ 	{IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_mac_cfg)},/* high 5GHz active */
+ 
+-/* 6x30 Series */
+-	{IWL_PCI_DEVICE(0x008A, 0x5305, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x008A, 0x5307, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x008A, 0x5325, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x008A, 0x5327, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x008B, 0x5315, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x008B, 0x5317, iwl1000_mac_cfg)},
++/* 1030/6x30 Series */
++	{IWL_PCI_DEVICE(0x008A, 0x5305, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x008A, 0x5307, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x008A, 0x5325, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x008A, 0x5327, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x008B, 0x5315, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x008B, 0x5317, iwl6030_mac_cfg)},
+ 	{IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_mac_cfg)},
+ 	{IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_mac_cfg)},
+ 	{IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_mac_cfg)},
+@@ -181,12 +181,12 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = {
+ 	{IWL_PCI_DEVICE(0x08AE, 0x1027, iwl1000_mac_cfg)},
+ 
+ /* 130 Series WiFi */
+-	{IWL_PCI_DEVICE(0x0896, 0x5005, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x0896, 0x5007, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x0897, 0x5015, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x0897, 0x5017, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x0896, 0x5025, iwl1000_mac_cfg)},
+-	{IWL_PCI_DEVICE(0x0896, 0x5027, iwl1000_mac_cfg)},
++	{IWL_PCI_DEVICE(0x0896, 0x5005, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x0896, 0x5007, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x0897, 0x5015, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x0897, 0x5017, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x0896, 0x5025, iwl6030_mac_cfg)},
++	{IWL_PCI_DEVICE(0x0896, 0x5027, iwl6030_mac_cfg)},
+ 
+ /* 2x00 Series */
+ 	{IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_mac_cfg)},
+diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
+index a4a2bac4f4b279..2f8d0223c1a6de 100644
+--- a/drivers/pci/controller/pci-mvebu.c
++++ b/drivers/pci/controller/pci-mvebu.c
+@@ -1168,12 +1168,6 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
+ 	return devm_ioremap_resource(&pdev->dev, &port->regs);
+ }
+ 
+-#define DT_FLAGS_TO_TYPE(flags)       (((flags) >> 24) & 0x03)
+-#define    DT_TYPE_IO                 0x1
+-#define    DT_TYPE_MEM32              0x2
+-#define DT_CPUADDR_TO_TARGET(cpuaddr) (((cpuaddr) >> 56) & 0xFF)
+-#define DT_CPUADDR_TO_ATTR(cpuaddr)   (((cpuaddr) >> 48) & 0xFF)
+-
+ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
+ 			      unsigned long type,
+ 			      unsigned int *tgt,
+@@ -1189,19 +1183,12 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
+ 		return -EINVAL;
+ 
+ 	for_each_of_range(&parser, &range) {
+-		unsigned long rtype;
+ 		u32 slot = upper_32_bits(range.bus_addr);
+ 
+-		if (DT_FLAGS_TO_TYPE(range.flags) == DT_TYPE_IO)
+-			rtype = IORESOURCE_IO;
+-		else if (DT_FLAGS_TO_TYPE(range.flags) == DT_TYPE_MEM32)
+-			rtype = IORESOURCE_MEM;
+-		else
+-			continue;
+-
+-		if (slot == PCI_SLOT(devfn) && type == rtype) {
+-			*tgt = DT_CPUADDR_TO_TARGET(range.cpu_addr);
+-			*attr = DT_CPUADDR_TO_ATTR(range.cpu_addr);
++		if (slot == PCI_SLOT(devfn) &&
++		    type == (range.flags & IORESOURCE_TYPE_BITS)) {
++			*tgt = (range.parent_bus_addr >> 56) & 0xFF;
++			*attr = (range.parent_bus_addr >> 48) & 0xFF;
+ 			return 0;
+ 		}
+ 	}
+diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
+index d7493c2294ef23..3709fba42ebd85 100644
+--- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
++++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
+@@ -127,13 +127,13 @@ static int eusb2_repeater_init(struct phy *phy)
+ 			     rptr->cfg->init_tbl[i].value);
+ 
+ 	/* Override registers from devicetree values */
+-	if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &val))
++	if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val))
+ 		regmap_write(regmap, base + EUSB2_TUNE_USB2_PREEM, val);
+ 
+ 	if (!of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &val))
+ 		regmap_write(regmap, base + EUSB2_TUNE_HSDISC, val);
+ 
+-	if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val))
++	if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &val))
+ 		regmap_write(regmap, base + EUSB2_TUNE_IUSB2, val);
+ 
+ 	/* Wait for status OK */
+diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+index 461b9e0af610a1..498f23c43aa139 100644
+--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
++++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+@@ -3064,6 +3064,14 @@ struct qmp_pcie {
+ 	struct clk_fixed_rate aux_clk_fixed;
+ };
+ 
++static bool qphy_checkbits(const void __iomem *base, u32 offset, u32 val)
++{
++	u32 reg;
++
++	reg = readl(base + offset);
++	return (reg & val) == val;
++}
++
+ static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
+ {
+ 	u32 reg;
+@@ -4332,16 +4340,21 @@ static int qmp_pcie_init(struct phy *phy)
+ 	struct qmp_pcie *qmp = phy_get_drvdata(phy);
+ 	const struct qmp_phy_cfg *cfg = qmp->cfg;
+ 	void __iomem *pcs = qmp->pcs;
+-	bool phy_initialized = !!(readl(pcs + cfg->regs[QPHY_START_CTRL]));
+ 	int ret;
+ 
+-	qmp->skip_init = qmp->nocsr_reset && phy_initialized;
+ 	/*
+-	 * We need to check the existence of init sequences in two cases:
+-	 * 1. The PHY doesn't support no_csr reset.
+-	 * 2. The PHY supports no_csr reset but isn't initialized by bootloader.
+-	 * As we can't skip init in these two cases.
++	 * We can skip PHY initialization if all of the following conditions
++	 * are met:
++	 *  1. The PHY supports the nocsr_reset that preserves the PHY config.
++	 *  2. The PHY was started (and not powered down again) by the
++	 *     bootloader, with all of the expected bits set correctly.
++	 * In this case, we can continue without having the init sequence
++	 * defined in the driver.
+ 	 */
++	qmp->skip_init = qmp->nocsr_reset &&
++		qphy_checkbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START) &&
++		qphy_checkbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], cfg->pwrdn_ctrl);
++
+ 	if (!qmp->skip_init && !cfg->tbls.serdes_num) {
+ 		dev_err(qmp->dev, "Init sequence not available\n");
+ 		return -ENODATA;
+diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
+index ebc8a7e21a3181..3409924498e9cf 100644
+--- a/drivers/phy/tegra/xusb-tegra210.c
++++ b/drivers/phy/tegra/xusb-tegra210.c
+@@ -3164,18 +3164,22 @@ tegra210_xusb_padctl_probe(struct device *dev,
+ 	}
+ 
+ 	pdev = of_find_device_by_node(np);
++	of_node_put(np);
+ 	if (!pdev) {
+ 		dev_warn(dev, "PMC device is not available\n");
+ 		goto out;
+ 	}
+ 
+-	if (!platform_get_drvdata(pdev))
++	if (!platform_get_drvdata(pdev)) {
++		put_device(&pdev->dev);
+ 		return ERR_PTR(-EPROBE_DEFER);
++	}
+ 
+ 	padctl->regmap = dev_get_regmap(&pdev->dev, "usb_sleepwalk");
+ 	if (!padctl->regmap)
+ 		dev_info(dev, "failed to find PMC regmap\n");
+ 
++	put_device(&pdev->dev);
+ out:
+ 	return &padctl->base;
+ }
+diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c
+index c1a0ef979142ce..c444bb2530ca29 100644
+--- a/drivers/phy/ti/phy-omap-usb2.c
++++ b/drivers/phy/ti/phy-omap-usb2.c
+@@ -363,6 +363,13 @@ static void omap_usb2_init_errata(struct omap_usb *phy)
+ 		phy->flags |= OMAP_USB2_DISABLE_CHRG_DET;
+ }
+ 
++static void omap_usb2_put_device(void *_dev)
++{
++	struct device *dev = _dev;
++
++	put_device(dev);
++}
++
+ static int omap_usb2_probe(struct platform_device *pdev)
+ {
+ 	struct omap_usb	*phy;
+@@ -373,6 +380,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
+ 	struct device_node *control_node;
+ 	struct platform_device *control_pdev;
+ 	const struct usb_phy_data *phy_data;
++	int ret;
+ 
+ 	phy_data = device_get_match_data(&pdev->dev);
+ 	if (!phy_data)
+@@ -423,6 +431,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
+ 			return -EINVAL;
+ 		}
+ 		phy->control_dev = &control_pdev->dev;
++
++		ret = devm_add_action_or_reset(&pdev->dev, omap_usb2_put_device,
++					       phy->control_dev);
++		if (ret)
++			return ret;
+ 	} else {
+ 		if (of_property_read_u32_index(node,
+ 					       "syscon-phy-power", 1,
+diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c
+index da2cbacb982c6b..ae764d6524c99a 100644
+--- a/drivers/phy/ti/phy-ti-pipe3.c
++++ b/drivers/phy/ti/phy-ti-pipe3.c
+@@ -667,12 +667,20 @@ static int ti_pipe3_get_clk(struct ti_pipe3 *phy)
+ 	return 0;
+ }
+ 
++static void ti_pipe3_put_device(void *_dev)
++{
++	struct device *dev = _dev;
++
++	put_device(dev);
++}
++
+ static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy)
+ {
+ 	struct device *dev = phy->dev;
+ 	struct device_node *node = dev->of_node;
+ 	struct device_node *control_node;
+ 	struct platform_device *control_pdev;
++	int ret;
+ 
+ 	phy->phy_power_syscon = syscon_regmap_lookup_by_phandle(node,
+ 							"syscon-phy-power");
+@@ -704,6 +712,11 @@ static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy)
+ 		}
+ 
+ 		phy->control_dev = &control_pdev->dev;
++
++		ret = devm_add_action_or_reset(dev, ti_pipe3_put_device,
++					       phy->control_dev);
++		if (ret)
++			return ret;
+ 	}
+ 
+ 	if (phy->mode == PIPE3_MODE_PCIE) {
+diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c
+index d1e7ba1fb3e1af..27e3d939b7bb9e 100644
+--- a/drivers/regulator/sy7636a-regulator.c
++++ b/drivers/regulator/sy7636a-regulator.c
+@@ -83,9 +83,11 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
+ 	if (!regmap)
+ 		return -EPROBE_DEFER;
+ 
+-	gdp = devm_gpiod_get(pdev->dev.parent, "epd-pwr-good", GPIOD_IN);
++	device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
++
++	gdp = devm_gpiod_get(&pdev->dev, "epd-pwr-good", GPIOD_IN);
+ 	if (IS_ERR(gdp)) {
+-		dev_err(pdev->dev.parent, "Power good GPIO fault %ld\n", PTR_ERR(gdp));
++		dev_err(&pdev->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp));
+ 		return PTR_ERR(gdp);
+ 	}
+ 
+@@ -105,7 +107,6 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	config.dev = &pdev->dev;
+-	config.dev->of_node = pdev->dev.parent->of_node;
+ 	config.regmap = regmap;
+ 
+ 	rdev = devm_regulator_register(&pdev->dev, &desc, &config);
+diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
+index cd1f657f782df2..13c663a154c4e8 100644
+--- a/drivers/tty/hvc/hvc_console.c
++++ b/drivers/tty/hvc/hvc_console.c
+@@ -543,10 +543,10 @@ static ssize_t hvc_write(struct tty_struct *tty, const u8 *buf, size_t count)
+ 	}
+ 
+ 	/*
+-	 * Racy, but harmless, kick thread if there is still pending data.
++	 * Kick thread to flush if there's still pending data
++	 * or to wakeup the write queue.
+ 	 */
+-	if (hp->n_outbuf)
+-		hvc_kick();
++	hvc_kick();
+ 
+ 	return written;
+ }
+diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
+index 5ea8aadb6e69c1..9056cb82456f14 100644
+--- a/drivers/tty/serial/sc16is7xx.c
++++ b/drivers/tty/serial/sc16is7xx.c
+@@ -1177,17 +1177,6 @@ static int sc16is7xx_startup(struct uart_port *port)
+ 	sc16is7xx_port_write(port, SC16IS7XX_FCR_REG,
+ 			     SC16IS7XX_FCR_FIFO_BIT);
+ 
+-	/* Enable EFR */
+-	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
+-			     SC16IS7XX_LCR_CONF_MODE_B);
+-
+-	regcache_cache_bypass(one->regmap, true);
+-
+-	/* Enable write access to enhanced features and internal clock div */
+-	sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
+-			      SC16IS7XX_EFR_ENABLE_BIT,
+-			      SC16IS7XX_EFR_ENABLE_BIT);
+-
+ 	/* Enable TCR/TLR */
+ 	sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
+ 			      SC16IS7XX_MCR_TCRTLR_BIT,
+@@ -1199,7 +1188,8 @@ static int sc16is7xx_startup(struct uart_port *port)
+ 			     SC16IS7XX_TCR_RX_RESUME(24) |
+ 			     SC16IS7XX_TCR_RX_HALT(48));
+ 
+-	regcache_cache_bypass(one->regmap, false);
++	/* Disable TCR/TLR access */
++	sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_TCRTLR_BIT, 0);
+ 
+ 	/* Now, initialize the UART */
+ 	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8);
+diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c
+index 0a800ba53816a8..de16b02d857e07 100644
+--- a/drivers/usb/gadget/function/f_midi2.c
++++ b/drivers/usb/gadget/function/f_midi2.c
+@@ -1599,6 +1599,7 @@ static int f_midi2_create_card(struct f_midi2 *midi2)
+ 			strscpy(fb->info.name, ump_fb_name(b),
+ 				sizeof(fb->info.name));
+ 		}
++		snd_ump_update_group_attrs(ump);
+ 	}
+ 
+ 	for (i = 0; i < midi2->num_eps; i++) {
+@@ -1736,9 +1737,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
+ 	case USB_SPEED_HIGH:
+ 		midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(512);
+ 		midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(512);
+-		for (i = 0; i < midi2->num_eps; i++)
++		for (i = 0; i < midi2->num_eps; i++) {
+ 			midi2_midi2_ep_out_desc[i].wMaxPacketSize =
+ 				cpu_to_le16(512);
++			midi2_midi2_ep_in_desc[i].wMaxPacketSize =
++				cpu_to_le16(512);
++		}
+ 		fallthrough;
+ 	case USB_SPEED_FULL:
+ 		midi1_in_eps = midi2_midi1_ep_in_descs;
+@@ -1747,9 +1751,12 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
+ 	case USB_SPEED_SUPER:
+ 		midi2_midi1_ep_out_desc.wMaxPacketSize = cpu_to_le16(1024);
+ 		midi2_midi1_ep_in_desc.wMaxPacketSize = cpu_to_le16(1024);
+-		for (i = 0; i < midi2->num_eps; i++)
++		for (i = 0; i < midi2->num_eps; i++) {
+ 			midi2_midi2_ep_out_desc[i].wMaxPacketSize =
+ 				cpu_to_le16(1024);
++			midi2_midi2_ep_in_desc[i].wMaxPacketSize =
++				cpu_to_le16(1024);
++		}
+ 		midi1_in_eps = midi2_midi1_ep_in_ss_descs;
+ 		midi1_out_eps = midi2_midi1_ep_out_ss_descs;
+ 		break;
+diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
+index 27c9699365ab95..18cd4b925e5e63 100644
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -765,8 +765,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+ 	if (!dum->driver)
+ 		return -ESHUTDOWN;
+ 
+-	local_irq_save(flags);
+-	spin_lock(&dum->lock);
++	spin_lock_irqsave(&dum->lock, flags);
+ 	list_for_each_entry(iter, &ep->queue, queue) {
+ 		if (&iter->req != _req)
+ 			continue;
+@@ -776,15 +775,16 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+ 		retval = 0;
+ 		break;
+ 	}
+-	spin_unlock(&dum->lock);
+ 
+ 	if (retval == 0) {
+ 		dev_dbg(udc_dev(dum),
+ 				"dequeued req %p from %s, len %d buf %p\n",
+ 				req, _ep->name, _req->length, _req->buf);
++		spin_unlock(&dum->lock);
+ 		usb_gadget_giveback_request(_ep, _req);
++		spin_lock(&dum->lock);
+ 	}
+-	local_irq_restore(flags);
++	spin_unlock_irqrestore(&dum->lock, flags);
+ 	return retval;
+ }
+ 
+diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
+index 06a2edb9e86ef7..63edf2d8f24501 100644
+--- a/drivers/usb/host/xhci-dbgcap.c
++++ b/drivers/usb/host/xhci-dbgcap.c
+@@ -101,13 +101,34 @@ static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings)
+ 	return string_length;
+ }
+ 
++static void xhci_dbc_init_ep_contexts(struct xhci_dbc *dbc)
++{
++	struct xhci_ep_ctx      *ep_ctx;
++	unsigned int		max_burst;
++	dma_addr_t		deq;
++
++	max_burst               = DBC_CTRL_MAXBURST(readl(&dbc->regs->control));
++
++	/* Populate bulk out endpoint context: */
++	ep_ctx                  = dbc_bulkout_ctx(dbc);
++	deq                     = dbc_bulkout_enq(dbc);
++	ep_ctx->ep_info         = 0;
++	ep_ctx->ep_info2        = dbc_epctx_info2(BULK_OUT_EP, 1024, max_burst);
++	ep_ctx->deq             = cpu_to_le64(deq | dbc->ring_out->cycle_state);
++
++	/* Populate bulk in endpoint context: */
++	ep_ctx                  = dbc_bulkin_ctx(dbc);
++	deq                     = dbc_bulkin_enq(dbc);
++	ep_ctx->ep_info         = 0;
++	ep_ctx->ep_info2        = dbc_epctx_info2(BULK_IN_EP, 1024, max_burst);
++	ep_ctx->deq             = cpu_to_le64(deq | dbc->ring_in->cycle_state);
++}
++
+ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
+ {
+ 	struct dbc_info_context	*info;
+-	struct xhci_ep_ctx	*ep_ctx;
+ 	u32			dev_info;
+-	dma_addr_t		deq, dma;
+-	unsigned int		max_burst;
++	dma_addr_t		dma;
+ 
+ 	if (!dbc)
+ 		return;
+@@ -121,20 +142,8 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
+ 	info->serial		= cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3);
+ 	info->length		= cpu_to_le32(string_length);
+ 
+-	/* Populate bulk out endpoint context: */
+-	ep_ctx			= dbc_bulkout_ctx(dbc);
+-	max_burst		= DBC_CTRL_MAXBURST(readl(&dbc->regs->control));
+-	deq			= dbc_bulkout_enq(dbc);
+-	ep_ctx->ep_info		= 0;
+-	ep_ctx->ep_info2	= dbc_epctx_info2(BULK_OUT_EP, 1024, max_burst);
+-	ep_ctx->deq		= cpu_to_le64(deq | dbc->ring_out->cycle_state);
+-
+-	/* Populate bulk in endpoint context: */
+-	ep_ctx			= dbc_bulkin_ctx(dbc);
+-	deq			= dbc_bulkin_enq(dbc);
+-	ep_ctx->ep_info		= 0;
+-	ep_ctx->ep_info2	= dbc_epctx_info2(BULK_IN_EP, 1024, max_burst);
+-	ep_ctx->deq		= cpu_to_le64(deq | dbc->ring_in->cycle_state);
++	/* Populate bulk in and out endpoint contexts: */
++	xhci_dbc_init_ep_contexts(dbc);
+ 
+ 	/* Set DbC context and info registers: */
+ 	lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp);
+@@ -436,6 +445,42 @@ dbc_alloc_ctx(struct device *dev, gfp_t flags)
+ 	return ctx;
+ }
+ 
++static void xhci_dbc_ring_init(struct xhci_ring *ring)
++{
++	struct xhci_segment *seg = ring->first_seg;
++
++	/* clear all trbs on ring in case of old ring */
++	memset(seg->trbs, 0, TRB_SEGMENT_SIZE);
++
++	/* Only event ring does not use link TRB */
++	if (ring->type != TYPE_EVENT) {
++		union xhci_trb *trb = &seg->trbs[TRBS_PER_SEGMENT - 1];
++
++		trb->link.segment_ptr = cpu_to_le64(ring->first_seg->dma);
++		trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK));
++	}
++	xhci_initialize_ring_info(ring);
++}
++
++static int xhci_dbc_reinit_ep_rings(struct xhci_dbc *dbc)
++{
++	struct xhci_ring *in_ring = dbc->eps[BULK_IN].ring;
++	struct xhci_ring *out_ring = dbc->eps[BULK_OUT].ring;
++
++	if (!in_ring || !out_ring || !dbc->ctx) {
++		dev_warn(dbc->dev, "Can't re-init unallocated endpoints\n");
++		return -ENODEV;
++	}
++
++	xhci_dbc_ring_init(in_ring);
++	xhci_dbc_ring_init(out_ring);
++
++	/* set ep context enqueue, dequeue, and cycle to initial values */
++	xhci_dbc_init_ep_contexts(dbc);
++
++	return 0;
++}
++
+ static struct xhci_ring *
+ xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags)
+ {
+@@ -464,15 +509,10 @@ xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags)
+ 
+ 	seg->dma = dma;
+ 
+-	/* Only event ring does not use link TRB */
+-	if (type != TYPE_EVENT) {
+-		union xhci_trb *trb = &seg->trbs[TRBS_PER_SEGMENT - 1];
+-
+-		trb->link.segment_ptr = cpu_to_le64(dma);
+-		trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK));
+-	}
+ 	INIT_LIST_HEAD(&ring->td_list);
+-	xhci_initialize_ring_info(ring);
++
++	xhci_dbc_ring_init(ring);
++
+ 	return ring;
+ dma_fail:
+ 	kfree(seg);
+@@ -864,7 +904,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
+ 			dev_info(dbc->dev, "DbC cable unplugged\n");
+ 			dbc->state = DS_ENABLED;
+ 			xhci_dbc_flush_requests(dbc);
+-
++			xhci_dbc_reinit_ep_rings(dbc);
+ 			return EVT_DISC;
+ 		}
+ 
+@@ -874,7 +914,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
+ 			writel(portsc, &dbc->regs->portsc);
+ 			dbc->state = DS_ENABLED;
+ 			xhci_dbc_flush_requests(dbc);
+-
++			xhci_dbc_reinit_ep_rings(dbc);
+ 			return EVT_DISC;
+ 		}
+ 
+diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
+index 81eaad87a3d9d0..c4a6544aa10751 100644
+--- a/drivers/usb/host/xhci-mem.c
++++ b/drivers/usb/host/xhci-mem.c
+@@ -962,7 +962,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i
+ out:
+ 	/* we are now at a leaf device */
+ 	xhci_debugfs_remove_slot(xhci, slot_id);
+-	xhci_free_virt_device(xhci, vdev, slot_id);
++	xhci_free_virt_device(xhci, xhci->devs[slot_id], slot_id);
+ }
+ 
+ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index e5cd3309342364..fc869b7f803f04 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -1322,7 +1322,18 @@ static const struct usb_device_id option_ids[] = {
+ 	 .driver_info = NCTRL(0) | RSVD(3) },
+ 	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff),	/* Telit LE910C1-EUX (ECM) */
+ 	 .driver_info = NCTRL(0) },
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1034, 0xff),	/* Telit LE910C4-WWX (rmnet) */
++	 .driver_info = RSVD(2) },
+ 	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1035, 0xff) }, /* Telit LE910C4-WWX (ECM) */
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1036, 0xff) },  /* Telit LE910C4-WWX */
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1037, 0xff),	/* Telit LE910C4-WWX (rmnet) */
++	 .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) },
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1038, 0xff),	/* Telit LE910C4-WWX (rmnet) */
++	 .driver_info = NCTRL(0) | RSVD(3) },
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103b, 0xff),	/* Telit LE910C4-WWX */
++	 .driver_info = NCTRL(0) | NCTRL(1) },
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103c, 0xff),	/* Telit LE910C4-WWX */
++	 .driver_info = NCTRL(0) },
+ 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0),
+ 	  .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
+ 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1),
+@@ -1369,6 +1380,12 @@ static const struct usb_device_id option_ids[] = {
+ 	  .driver_info = NCTRL(0) | RSVD(1) },
+ 	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff),	/* Telit FN990A (PCIe) */
+ 	  .driver_info = RSVD(0) },
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1077, 0xff),	/* Telit FN990A (rmnet + audio) */
++	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1078, 0xff),	/* Telit FN990A (MBIM + audio) */
++	  .driver_info = NCTRL(0) | RSVD(1) },
++	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1079, 0xff),	/* Telit FN990A (RNDIS + audio) */
++	  .driver_info = NCTRL(2) | RSVD(3) },
+ 	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff),	/* Telit FE990A (rmnet) */
+ 	  .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
+ 	{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff),	/* Telit FE990A (MBIM) */
+diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
+index 1f6fdfaa34bf12..b2a568a5bc9b0b 100644
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -2426,17 +2426,21 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
+ 		case ADEV_NONE:
+ 			break;
+ 		case ADEV_NOTIFY_USB_AND_QUEUE_VDM:
+-			WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL));
+-			typec_altmode_vdm(adev, p[0], &p[1], cnt);
++			if (rx_sop_type == TCPC_TX_SOP_PRIME) {
++				typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt);
++			} else {
++				WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL));
++				typec_altmode_vdm(adev, p[0], &p[1], cnt);
++			}
+ 			break;
+ 		case ADEV_QUEUE_VDM:
+-			if (response_tx_sop_type == TCPC_TX_SOP_PRIME)
++			if (rx_sop_type == TCPC_TX_SOP_PRIME)
+ 				typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt);
+ 			else
+ 				typec_altmode_vdm(adev, p[0], &p[1], cnt);
+ 			break;
+ 		case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL:
+-			if (response_tx_sop_type == TCPC_TX_SOP_PRIME) {
++			if (rx_sop_type == TCPC_TX_SOP_PRIME) {
+ 				if (typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P,
+ 							    p[0], &p[1], cnt)) {
+ 					int svdm_version = typec_get_cable_svdm_version(
+diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
+index fac4000a5bcaef..b843db855f402f 100644
+--- a/fs/btrfs/extent_io.c
++++ b/fs/btrfs/extent_io.c
+@@ -110,6 +110,25 @@ struct btrfs_bio_ctrl {
+ 	 * This is to avoid touching ranges covered by compression/inline.
+ 	 */
+ 	unsigned long submit_bitmap;
++	struct readahead_control *ractl;
++
++	/*
++	 * The start offset of the last used extent map by a read operation.
++	 *
++	 * This is for proper compressed read merge.
++	 * U64_MAX means we are starting the read and have made no progress yet.
++	 *
++	 * The current btrfs_bio_is_contig() only uses disk_bytenr as
++	 * the condition to check if the read can be merged with previous
++	 * bio, which is not correct. E.g. two file extents pointing to the
++	 * same extent but with different offset.
++	 *
++	 * So here we need to do extra checks to only merge reads that are
++	 * covered by the same extent map.
++	 * Just extent_map::start will be enough, as they are unique
++	 * inside the same inode.
++	 */
++	u64 last_em_start;
+ };
+ 
+ static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
+@@ -882,6 +901,25 @@ static struct extent_map *get_extent_map(struct btrfs_inode *inode,
+ 
+ 	return em;
+ }
++
++static void btrfs_readahead_expand(struct readahead_control *ractl,
++				   const struct extent_map *em)
++{
++	const u64 ra_pos = readahead_pos(ractl);
++	const u64 ra_end = ra_pos + readahead_length(ractl);
++	const u64 em_end = em->start + em->ram_bytes;
++
++	/* No expansion for holes and inline extents. */
++	if (em->disk_bytenr > EXTENT_MAP_LAST_BYTE)
++		return;
++
++	ASSERT(em_end >= ra_pos,
++	       "extent_map %llu %llu ends before current readahead position %llu",
++	       em->start, em->len, ra_pos);
++	if (em_end > ra_end)
++		readahead_expand(ractl, ra_pos, em_end - ra_pos);
++}
++
+ /*
+  * basic readpage implementation.  Locked extent state structs are inserted
+  * into the tree that are removed when the IO is done (by the end_io
+@@ -890,7 +928,7 @@ static struct extent_map *get_extent_map(struct btrfs_inode *inode,
+  * return 0 on success, otherwise return error
+  */
+ static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
+-		      struct btrfs_bio_ctrl *bio_ctrl, u64 *prev_em_start)
++			     struct btrfs_bio_ctrl *bio_ctrl)
+ {
+ 	struct inode *inode = folio->mapping->host;
+ 	struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
+@@ -945,6 +983,16 @@ static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
+ 
+ 		compress_type = btrfs_extent_map_compression(em);
+ 
++		/*
++		 * Only expand readahead for extents which are already creating
++		 * the pages anyway in add_ra_bio_pages, which is compressed
++		 * extents in the non subpage case.
++		 */
++		if (bio_ctrl->ractl &&
++		    !btrfs_is_subpage(fs_info, folio) &&
++		    compress_type != BTRFS_COMPRESS_NONE)
++			btrfs_readahead_expand(bio_ctrl->ractl, em);
++
+ 		if (compress_type != BTRFS_COMPRESS_NONE)
+ 			disk_bytenr = em->disk_bytenr;
+ 		else
+@@ -990,12 +1038,11 @@ static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
+ 		 * non-optimal behavior (submitting 2 bios for the same extent).
+ 		 */
+ 		if (compress_type != BTRFS_COMPRESS_NONE &&
+-		    prev_em_start && *prev_em_start != (u64)-1 &&
+-		    *prev_em_start != em->start)
++		    bio_ctrl->last_em_start != U64_MAX &&
++		    bio_ctrl->last_em_start != em->start)
+ 			force_bio_submit = true;
+ 
+-		if (prev_em_start)
+-			*prev_em_start = em->start;
++		bio_ctrl->last_em_start = em->start;
+ 
+ 		btrfs_free_extent_map(em);
+ 		em = NULL;
+@@ -1209,12 +1256,15 @@ int btrfs_read_folio(struct file *file, struct folio *folio)
+ 	const u64 start = folio_pos(folio);
+ 	const u64 end = start + folio_size(folio) - 1;
+ 	struct extent_state *cached_state = NULL;
+-	struct btrfs_bio_ctrl bio_ctrl = { .opf = REQ_OP_READ };
++	struct btrfs_bio_ctrl bio_ctrl = {
++		.opf = REQ_OP_READ,
++		.last_em_start = U64_MAX,
++	};
+ 	struct extent_map *em_cached = NULL;
+ 	int ret;
+ 
+ 	lock_extents_for_read(inode, start, end, &cached_state);
+-	ret = btrfs_do_readpage(folio, &em_cached, &bio_ctrl, NULL);
++	ret = btrfs_do_readpage(folio, &em_cached, &bio_ctrl);
+ 	btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);
+ 
+ 	btrfs_free_extent_map(em_cached);
+@@ -2550,19 +2600,22 @@ int btrfs_writepages(struct address_space *mapping, struct writeback_control *wb
+ 
+ void btrfs_readahead(struct readahead_control *rac)
+ {
+-	struct btrfs_bio_ctrl bio_ctrl = { .opf = REQ_OP_READ | REQ_RAHEAD };
++	struct btrfs_bio_ctrl bio_ctrl = {
++		.opf = REQ_OP_READ | REQ_RAHEAD,
++		.ractl = rac,
++		.last_em_start = U64_MAX,
++	};
+ 	struct folio *folio;
+ 	struct btrfs_inode *inode = BTRFS_I(rac->mapping->host);
+ 	const u64 start = readahead_pos(rac);
+ 	const u64 end = start + readahead_length(rac) - 1;
+ 	struct extent_state *cached_state = NULL;
+ 	struct extent_map *em_cached = NULL;
+-	u64 prev_em_start = (u64)-1;
+ 
+ 	lock_extents_for_read(inode, start, end, &cached_state);
+ 
+ 	while ((folio = readahead_folio(rac)) != NULL)
+-		btrfs_do_readpage(folio, &em_cached, &bio_ctrl, &prev_em_start);
++		btrfs_do_readpage(folio, &em_cached, &bio_ctrl);
+ 
+ 	btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);
+ 
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index ffa5d6c1594050..e266a229484852 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -5685,7 +5685,17 @@ static void btrfs_del_inode_from_root(struct btrfs_inode *inode)
+ 	bool empty = false;
+ 
+ 	xa_lock(&root->inodes);
+-	entry = __xa_erase(&root->inodes, btrfs_ino(inode));
++	/*
++	 * This btrfs_inode is being freed and has already been unhashed at this
++	 * point. It's possible that another btrfs_inode has already been
++	 * allocated for the same inode and inserted itself into the root, so
++	 * don't delete it in that case.
++	 *
++	 * Note that this shouldn't need to allocate memory, so the gfp flags
++	 * don't really matter.
++	 */
++	entry = __xa_cmpxchg(&root->inodes, btrfs_ino(inode), inode, NULL,
++			     GFP_ATOMIC);
+ 	if (entry == inode)
+ 		empty = xa_empty(&root->inodes);
+ 	xa_unlock(&root->inodes);
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index 68cbb2b1e3df8e..1fc99ba185164b 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1483,6 +1483,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
+ 	struct btrfs_qgroup *qgroup;
+ 	LIST_HEAD(qgroup_list);
+ 	u64 num_bytes = src->excl;
++	u64 num_bytes_cmpr = src->excl_cmpr;
+ 	int ret = 0;
+ 
+ 	qgroup = find_qgroup_rb(fs_info, ref_root);
+@@ -1494,11 +1495,12 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
+ 		struct btrfs_qgroup_list *glist;
+ 
+ 		qgroup->rfer += sign * num_bytes;
+-		qgroup->rfer_cmpr += sign * num_bytes;
++		qgroup->rfer_cmpr += sign * num_bytes_cmpr;
+ 
+ 		WARN_ON(sign < 0 && qgroup->excl < num_bytes);
++		WARN_ON(sign < 0 && qgroup->excl_cmpr < num_bytes_cmpr);
+ 		qgroup->excl += sign * num_bytes;
+-		qgroup->excl_cmpr += sign * num_bytes;
++		qgroup->excl_cmpr += sign * num_bytes_cmpr;
+ 
+ 		if (sign > 0)
+ 			qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
+index 60a621b00c656d..1777d707fd7561 100644
+--- a/fs/ceph/addr.c
++++ b/fs/ceph/addr.c
+@@ -1264,7 +1264,9 @@ static inline int move_dirty_folio_in_page_array(struct address_space *mapping,
+ 								0,
+ 								gfp_flags);
+ 		if (IS_ERR(pages[index])) {
+-			if (PTR_ERR(pages[index]) == -EINVAL) {
++			int err = PTR_ERR(pages[index]);
++
++			if (err == -EINVAL) {
+ 				pr_err_client(cl, "inode->i_blkbits=%hhu\n",
+ 						inode->i_blkbits);
+ 			}
+@@ -1273,7 +1275,7 @@ static inline int move_dirty_folio_in_page_array(struct address_space *mapping,
+ 			BUG_ON(ceph_wbc->locked_pages == 0);
+ 
+ 			pages[index] = NULL;
+-			return PTR_ERR(pages[index]);
++			return err;
+ 		}
+ 	} else {
+ 		pages[index] = &folio->page;
+@@ -1687,6 +1689,7 @@ static int ceph_writepages_start(struct address_space *mapping,
+ 
+ process_folio_batch:
+ 		rc = ceph_process_folio_batch(mapping, wbc, &ceph_wbc);
++		ceph_shift_unused_folios_left(&ceph_wbc.fbatch);
+ 		if (rc)
+ 			goto release_folios;
+ 
+@@ -1695,8 +1698,6 @@ static int ceph_writepages_start(struct address_space *mapping,
+ 			goto release_folios;
+ 
+ 		if (ceph_wbc.processed_in_fbatch) {
+-			ceph_shift_unused_folios_left(&ceph_wbc.fbatch);
+-
+ 			if (folio_batch_count(&ceph_wbc.fbatch) == 0 &&
+ 			    ceph_wbc.locked_pages < ceph_wbc.max_pages) {
+ 				doutc(cl, "reached end fbatch, trying for more\n");
+diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
+index fdd404fc81124d..f3fe786b4143d4 100644
+--- a/fs/ceph/debugfs.c
++++ b/fs/ceph/debugfs.c
+@@ -55,8 +55,6 @@ static int mdsc_show(struct seq_file *s, void *p)
+ 	struct ceph_mds_client *mdsc = fsc->mdsc;
+ 	struct ceph_mds_request *req;
+ 	struct rb_node *rp;
+-	int pathlen = 0;
+-	u64 pathbase;
+ 	char *path;
+ 
+ 	mutex_lock(&mdsc->mutex);
+@@ -81,8 +79,8 @@ static int mdsc_show(struct seq_file *s, void *p)
+ 		if (req->r_inode) {
+ 			seq_printf(s, " #%llx", ceph_ino(req->r_inode));
+ 		} else if (req->r_dentry) {
+-			path = ceph_mdsc_build_path(mdsc, req->r_dentry, &pathlen,
+-						    &pathbase, 0);
++			struct ceph_path_info path_info;
++			path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
+ 			if (IS_ERR(path))
+ 				path = NULL;
+ 			spin_lock(&req->r_dentry->d_lock);
+@@ -91,7 +89,7 @@ static int mdsc_show(struct seq_file *s, void *p)
+ 				   req->r_dentry,
+ 				   path ? path : "");
+ 			spin_unlock(&req->r_dentry->d_lock);
+-			ceph_mdsc_free_path(path, pathlen);
++			ceph_mdsc_free_path_info(&path_info);
+ 		} else if (req->r_path1) {
+ 			seq_printf(s, " #%llx/%s", req->r_ino1.ino,
+ 				   req->r_path1);
+@@ -100,8 +98,8 @@ static int mdsc_show(struct seq_file *s, void *p)
+ 		}
+ 
+ 		if (req->r_old_dentry) {
+-			path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &pathlen,
+-						    &pathbase, 0);
++			struct ceph_path_info path_info;
++			path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0);
+ 			if (IS_ERR(path))
+ 				path = NULL;
+ 			spin_lock(&req->r_old_dentry->d_lock);
+@@ -111,7 +109,7 @@ static int mdsc_show(struct seq_file *s, void *p)
+ 				   req->r_old_dentry,
+ 				   path ? path : "");
+ 			spin_unlock(&req->r_old_dentry->d_lock);
+-			ceph_mdsc_free_path(path, pathlen);
++			ceph_mdsc_free_path_info(&path_info);
+ 		} else if (req->r_path2 && req->r_op != CEPH_MDS_OP_SYMLINK) {
+ 			if (req->r_ino2.ino)
+ 				seq_printf(s, " #%llx/%s", req->r_ino2.ino,
+diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
+index a321aa6d0ed226..e7af63bf77b469 100644
+--- a/fs/ceph/dir.c
++++ b/fs/ceph/dir.c
+@@ -1272,10 +1272,8 @@ static void ceph_async_unlink_cb(struct ceph_mds_client *mdsc,
+ 
+ 	/* If op failed, mark everyone involved for errors */
+ 	if (result) {
+-		int pathlen = 0;
+-		u64 base = 0;
+-		char *path = ceph_mdsc_build_path(mdsc, dentry, &pathlen,
+-						  &base, 0);
++		struct ceph_path_info path_info = {0};
++		char *path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
+ 
+ 		/* mark error on parent + clear complete */
+ 		mapping_set_error(req->r_parent->i_mapping, result);
+@@ -1289,8 +1287,8 @@ static void ceph_async_unlink_cb(struct ceph_mds_client *mdsc,
+ 		mapping_set_error(req->r_old_inode->i_mapping, result);
+ 
+ 		pr_warn_client(cl, "failure path=(%llx)%s result=%d!\n",
+-			       base, IS_ERR(path) ? "<<bad>>" : path, result);
+-		ceph_mdsc_free_path(path, pathlen);
++			       path_info.vino.ino, IS_ERR(path) ? "<<bad>>" : path, result);
++		ceph_mdsc_free_path_info(&path_info);
+ 	}
+ out:
+ 	iput(req->r_old_inode);
+@@ -1348,8 +1346,6 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
+ 	int err = -EROFS;
+ 	int op;
+ 	char *path;
+-	int pathlen;
+-	u64 pathbase;
+ 
+ 	if (ceph_snap(dir) == CEPH_SNAPDIR) {
+ 		/* rmdir .snap/foo is RMSNAP */
+@@ -1368,14 +1364,15 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
+ 	if (!dn) {
+ 		try_async = false;
+ 	} else {
+-		path = ceph_mdsc_build_path(mdsc, dn, &pathlen, &pathbase, 0);
++		struct ceph_path_info path_info;
++		path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
+ 		if (IS_ERR(path)) {
+ 			try_async = false;
+ 			err = 0;
+ 		} else {
+ 			err = ceph_mds_check_access(mdsc, path, MAY_WRITE);
+ 		}
+-		ceph_mdsc_free_path(path, pathlen);
++		ceph_mdsc_free_path_info(&path_info);
+ 		dput(dn);
+ 
+ 		/* For none EACCES cases will let the MDS do the mds auth check */
+diff --git a/fs/ceph/file.c b/fs/ceph/file.c
+index a7254cab44cc2e..6587c2d5af1e08 100644
+--- a/fs/ceph/file.c
++++ b/fs/ceph/file.c
+@@ -368,8 +368,6 @@ int ceph_open(struct inode *inode, struct file *file)
+ 	int flags, fmode, wanted;
+ 	struct dentry *dentry;
+ 	char *path;
+-	int pathlen;
+-	u64 pathbase;
+ 	bool do_sync = false;
+ 	int mask = MAY_READ;
+ 
+@@ -399,14 +397,15 @@ int ceph_open(struct inode *inode, struct file *file)
+ 	if (!dentry) {
+ 		do_sync = true;
+ 	} else {
+-		path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, 0);
++		struct ceph_path_info path_info;
++		path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
+ 		if (IS_ERR(path)) {
+ 			do_sync = true;
+ 			err = 0;
+ 		} else {
+ 			err = ceph_mds_check_access(mdsc, path, mask);
+ 		}
+-		ceph_mdsc_free_path(path, pathlen);
++		ceph_mdsc_free_path_info(&path_info);
+ 		dput(dentry);
+ 
+ 		/* For none EACCES cases will let the MDS do the mds auth check */
+@@ -614,15 +613,13 @@ static void ceph_async_create_cb(struct ceph_mds_client *mdsc,
+ 	mapping_set_error(req->r_parent->i_mapping, result);
+ 
+ 	if (result) {
+-		int pathlen = 0;
+-		u64 base = 0;
+-		char *path = ceph_mdsc_build_path(mdsc, req->r_dentry, &pathlen,
+-						  &base, 0);
++		struct ceph_path_info path_info = {0};
++		char *path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
+ 
+ 		pr_warn_client(cl,
+ 			"async create failure path=(%llx)%s result=%d!\n",
+-			base, IS_ERR(path) ? "<<bad>>" : path, result);
+-		ceph_mdsc_free_path(path, pathlen);
++			path_info.vino.ino, IS_ERR(path) ? "<<bad>>" : path, result);
++		ceph_mdsc_free_path_info(&path_info);
+ 
+ 		ceph_dir_clear_complete(req->r_parent);
+ 		if (!d_unhashed(dentry))
+@@ -791,8 +788,6 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
+ 	int mask;
+ 	int err;
+ 	char *path;
+-	int pathlen;
+-	u64 pathbase;
+ 
+ 	doutc(cl, "%p %llx.%llx dentry %p '%pd' %s flags %d mode 0%o\n",
+ 	      dir, ceph_vinop(dir), dentry, dentry,
+@@ -814,7 +809,8 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
+ 	if (!dn) {
+ 		try_async = false;
+ 	} else {
+-		path = ceph_mdsc_build_path(mdsc, dn, &pathlen, &pathbase, 0);
++		struct ceph_path_info path_info;
++		path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
+ 		if (IS_ERR(path)) {
+ 			try_async = false;
+ 			err = 0;
+@@ -826,7 +822,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
+ 				mask |= MAY_WRITE;
+ 			err = ceph_mds_check_access(mdsc, path, mask);
+ 		}
+-		ceph_mdsc_free_path(path, pathlen);
++		ceph_mdsc_free_path_info(&path_info);
+ 		dput(dn);
+ 
+ 		/* For none EACCES cases will let the MDS do the mds auth check */
+diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
+index 06cd2963e41ee0..14e59c15dd68dd 100644
+--- a/fs/ceph/inode.c
++++ b/fs/ceph/inode.c
+@@ -55,6 +55,52 @@ static int ceph_set_ino_cb(struct inode *inode, void *data)
+ 	return 0;
+ }
+ 
++/*
++ * Check if the parent inode matches the vino from directory reply info
++ */
++static inline bool ceph_vino_matches_parent(struct inode *parent,
++					    struct ceph_vino vino)
++{
++	return ceph_ino(parent) == vino.ino && ceph_snap(parent) == vino.snap;
++}
++
++/*
++ * Validate that the directory inode referenced by @req->r_parent matches the
++ * inode number and snapshot id contained in the reply's directory record.  If
++ * they do not match – which can theoretically happen if the parent dentry was
++ * moved between the time the request was issued and the reply arrived – fall
++ * back to looking up the correct inode in the inode cache.
++ *
++ * A reference is *always* returned.  Callers that receive a different inode
++ * than the original @parent are responsible for dropping the extra reference
++ * once the reply has been processed.
++ */
++static struct inode *ceph_get_reply_dir(struct super_block *sb,
++					struct inode *parent,
++					struct ceph_mds_reply_info_parsed *rinfo)
++{
++	struct ceph_vino vino;
++
++	if (unlikely(!rinfo->diri.in))
++		return parent; /* nothing to compare against */
++
++	/* If we didn't have a cached parent inode to begin with, just bail out. */
++	if (!parent)
++		return NULL;
++
++	vino.ino  = le64_to_cpu(rinfo->diri.in->ino);
++	vino.snap = le64_to_cpu(rinfo->diri.in->snapid);
++
++	if (likely(ceph_vino_matches_parent(parent, vino)))
++		return parent; /* matches – use the original reference */
++
++	/* Mismatch – this should be rare.  Emit a WARN and obtain the correct inode. */
++	WARN_ONCE(1, "ceph: reply dir mismatch (parent valid %llx.%llx reply %llx.%llx)\n",
++		  ceph_ino(parent), ceph_snap(parent), vino.ino, vino.snap);
++
++	return ceph_get_inode(sb, vino, NULL);
++}
++
+ /**
+  * ceph_new_inode - allocate a new inode in advance of an expected create
+  * @dir: parent directory for new inode
+@@ -1523,6 +1569,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 	struct ceph_vino tvino, dvino;
+ 	struct ceph_fs_client *fsc = ceph_sb_to_fs_client(sb);
+ 	struct ceph_client *cl = fsc->client;
++	struct inode *parent_dir = NULL;
+ 	int err = 0;
+ 
+ 	doutc(cl, "%p is_dentry %d is_target %d\n", req,
+@@ -1536,10 +1583,17 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 	}
+ 
+ 	if (rinfo->head->is_dentry) {
+-		struct inode *dir = req->r_parent;
+-
+-		if (dir) {
+-			err = ceph_fill_inode(dir, NULL, &rinfo->diri,
++		/*
++		 * r_parent may be stale, in cases when R_PARENT_LOCKED is not set,
++		 * so we need to get the correct inode
++		 */
++		parent_dir = ceph_get_reply_dir(sb, req->r_parent, rinfo);
++		if (unlikely(IS_ERR(parent_dir))) {
++			err = PTR_ERR(parent_dir);
++			goto done;
++		}
++		if (parent_dir) {
++			err = ceph_fill_inode(parent_dir, NULL, &rinfo->diri,
+ 					      rinfo->dirfrag, session, -1,
+ 					      &req->r_caps_reservation);
+ 			if (err < 0)
+@@ -1548,14 +1602,14 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 			WARN_ON_ONCE(1);
+ 		}
+ 
+-		if (dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME &&
++		if (parent_dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME &&
+ 		    test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) &&
+ 		    !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) {
+ 			bool is_nokey = false;
+ 			struct qstr dname;
+ 			struct dentry *dn, *parent;
+ 			struct fscrypt_str oname = FSTR_INIT(NULL, 0);
+-			struct ceph_fname fname = { .dir	= dir,
++			struct ceph_fname fname = { .dir	= parent_dir,
+ 						    .name	= rinfo->dname,
+ 						    .ctext	= rinfo->altname,
+ 						    .name_len	= rinfo->dname_len,
+@@ -1564,10 +1618,10 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 			BUG_ON(!rinfo->head->is_target);
+ 			BUG_ON(req->r_dentry);
+ 
+-			parent = d_find_any_alias(dir);
++			parent = d_find_any_alias(parent_dir);
+ 			BUG_ON(!parent);
+ 
+-			err = ceph_fname_alloc_buffer(dir, &oname);
++			err = ceph_fname_alloc_buffer(parent_dir, &oname);
+ 			if (err < 0) {
+ 				dput(parent);
+ 				goto done;
+@@ -1576,7 +1630,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 			err = ceph_fname_to_usr(&fname, NULL, &oname, &is_nokey);
+ 			if (err < 0) {
+ 				dput(parent);
+-				ceph_fname_free_buffer(dir, &oname);
++				ceph_fname_free_buffer(parent_dir, &oname);
+ 				goto done;
+ 			}
+ 			dname.name = oname.name;
+@@ -1595,7 +1649,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 				      dname.len, dname.name, dn);
+ 				if (!dn) {
+ 					dput(parent);
+-					ceph_fname_free_buffer(dir, &oname);
++					ceph_fname_free_buffer(parent_dir, &oname);
+ 					err = -ENOMEM;
+ 					goto done;
+ 				}
+@@ -1610,12 +1664,12 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 				    ceph_snap(d_inode(dn)) != tvino.snap)) {
+ 				doutc(cl, " dn %p points to wrong inode %p\n",
+ 				      dn, d_inode(dn));
+-				ceph_dir_clear_ordered(dir);
++				ceph_dir_clear_ordered(parent_dir);
+ 				d_delete(dn);
+ 				dput(dn);
+ 				goto retry_lookup;
+ 			}
+-			ceph_fname_free_buffer(dir, &oname);
++			ceph_fname_free_buffer(parent_dir, &oname);
+ 
+ 			req->r_dentry = dn;
+ 			dput(parent);
+@@ -1794,6 +1848,9 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req)
+ 					    &dvino, ptvino);
+ 	}
+ done:
++	/* Drop extra ref from ceph_get_reply_dir() if it returned a new inode */
++	if (unlikely(!IS_ERR_OR_NULL(parent_dir) && parent_dir != req->r_parent))
++		iput(parent_dir);
+ 	doutc(cl, "done err=%d\n", err);
+ 	return err;
+ }
+@@ -2488,22 +2545,21 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
+ 	int truncate_retry = 20; /* The RMW will take around 50ms */
+ 	struct dentry *dentry;
+ 	char *path;
+-	int pathlen;
+-	u64 pathbase;
+ 	bool do_sync = false;
+ 
+ 	dentry = d_find_alias(inode);
+ 	if (!dentry) {
+ 		do_sync = true;
+ 	} else {
+-		path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase, 0);
++		struct ceph_path_info path_info;
++		path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
+ 		if (IS_ERR(path)) {
+ 			do_sync = true;
+ 			err = 0;
+ 		} else {
+ 			err = ceph_mds_check_access(mdsc, path, MAY_WRITE);
+ 		}
+-		ceph_mdsc_free_path(path, pathlen);
++		ceph_mdsc_free_path_info(&path_info);
+ 		dput(dentry);
+ 
+ 		/* For none EACCES cases will let the MDS do the mds auth check */
+diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
+index 230e0c3f341f71..94f109ca853eba 100644
+--- a/fs/ceph/mds_client.c
++++ b/fs/ceph/mds_client.c
+@@ -2681,8 +2681,7 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
+  * ceph_mdsc_build_path - build a path string to a given dentry
+  * @mdsc: mds client
+  * @dentry: dentry to which path should be built
+- * @plen: returned length of string
+- * @pbase: returned base inode number
++ * @path_info: output path, length, base ino+snap, and freepath ownership flag
+  * @for_wire: is this path going to be sent to the MDS?
+  *
+  * Build a string that represents the path to the dentry. This is mostly called
+@@ -2700,7 +2699,7 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
+  *   foo/.snap/bar -> foo//bar
+  */
+ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
+-			   int *plen, u64 *pbase, int for_wire)
++			   struct ceph_path_info *path_info, int for_wire)
+ {
+ 	struct ceph_client *cl = mdsc->fsc->client;
+ 	struct dentry *cur;
+@@ -2810,16 +2809,28 @@ char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
+ 		return ERR_PTR(-ENAMETOOLONG);
+ 	}
+ 
+-	*pbase = base;
+-	*plen = PATH_MAX - 1 - pos;
++	/* Initialize the output structure */
++	memset(path_info, 0, sizeof(*path_info));
++
++	path_info->vino.ino = base;
++	path_info->pathlen = PATH_MAX - 1 - pos;
++	path_info->path = path + pos;
++	path_info->freepath = true;
++
++	/* Set snap from dentry if available */
++	if (d_inode(dentry))
++		path_info->vino.snap = ceph_snap(d_inode(dentry));
++	else
++		path_info->vino.snap = CEPH_NOSNAP;
++
+ 	doutc(cl, "on %p %d built %llx '%.*s'\n", dentry, d_count(dentry),
+-	      base, *plen, path + pos);
++	      base, PATH_MAX - 1 - pos, path + pos);
+ 	return path + pos;
+ }
+ 
+ static int build_dentry_path(struct ceph_mds_client *mdsc, struct dentry *dentry,
+-			     struct inode *dir, const char **ppath, int *ppathlen,
+-			     u64 *pino, bool *pfreepath, bool parent_locked)
++			     struct inode *dir, struct ceph_path_info *path_info,
++			     bool parent_locked)
+ {
+ 	char *path;
+ 
+@@ -2828,41 +2839,47 @@ static int build_dentry_path(struct ceph_mds_client *mdsc, struct dentry *dentry
+ 		dir = d_inode_rcu(dentry->d_parent);
+ 	if (dir && parent_locked && ceph_snap(dir) == CEPH_NOSNAP &&
+ 	    !IS_ENCRYPTED(dir)) {
+-		*pino = ceph_ino(dir);
++		path_info->vino.ino = ceph_ino(dir);
++		path_info->vino.snap = ceph_snap(dir);
+ 		rcu_read_unlock();
+-		*ppath = dentry->d_name.name;
+-		*ppathlen = dentry->d_name.len;
++		path_info->path = dentry->d_name.name;
++		path_info->pathlen = dentry->d_name.len;
++		path_info->freepath = false;
+ 		return 0;
+ 	}
+ 	rcu_read_unlock();
+-	path = ceph_mdsc_build_path(mdsc, dentry, ppathlen, pino, 1);
++	path = ceph_mdsc_build_path(mdsc, dentry, path_info, 1);
+ 	if (IS_ERR(path))
+ 		return PTR_ERR(path);
+-	*ppath = path;
+-	*pfreepath = true;
++	/*
++	 * ceph_mdsc_build_path already fills path_info, including snap handling.
++	 */
+ 	return 0;
+ }
+ 
+-static int build_inode_path(struct inode *inode,
+-			    const char **ppath, int *ppathlen, u64 *pino,
+-			    bool *pfreepath)
++static int build_inode_path(struct inode *inode, struct ceph_path_info *path_info)
+ {
+ 	struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(inode->i_sb);
+ 	struct dentry *dentry;
+ 	char *path;
+ 
+ 	if (ceph_snap(inode) == CEPH_NOSNAP) {
+-		*pino = ceph_ino(inode);
+-		*ppathlen = 0;
++		path_info->vino.ino = ceph_ino(inode);
++		path_info->vino.snap = ceph_snap(inode);
++		path_info->pathlen = 0;
++		path_info->freepath = false;
+ 		return 0;
+ 	}
+ 	dentry = d_find_alias(inode);
+-	path = ceph_mdsc_build_path(mdsc, dentry, ppathlen, pino, 1);
++	path = ceph_mdsc_build_path(mdsc, dentry, path_info, 1);
+ 	dput(dentry);
+ 	if (IS_ERR(path))
+ 		return PTR_ERR(path);
+-	*ppath = path;
+-	*pfreepath = true;
++	/*
++	 * ceph_mdsc_build_path already fills path_info, including snap from dentry.
++	 * Override with inode's snap since that's what this function is for.
++	 */
++	path_info->vino.snap = ceph_snap(inode);
+ 	return 0;
+ }
+ 
+@@ -2872,26 +2889,32 @@ static int build_inode_path(struct inode *inode,
+  */
+ static int set_request_path_attr(struct ceph_mds_client *mdsc, struct inode *rinode,
+ 				 struct dentry *rdentry, struct inode *rdiri,
+-				 const char *rpath, u64 rino, const char **ppath,
+-				 int *pathlen, u64 *ino, bool *freepath,
++				 const char *rpath, u64 rino,
++				 struct ceph_path_info *path_info,
+ 				 bool parent_locked)
+ {
+ 	struct ceph_client *cl = mdsc->fsc->client;
+ 	int r = 0;
+ 
++	/* Initialize the output structure */
++	memset(path_info, 0, sizeof(*path_info));
++
+ 	if (rinode) {
+-		r = build_inode_path(rinode, ppath, pathlen, ino, freepath);
++		r = build_inode_path(rinode, path_info);
+ 		doutc(cl, " inode %p %llx.%llx\n", rinode, ceph_ino(rinode),
+ 		      ceph_snap(rinode));
+ 	} else if (rdentry) {
+-		r = build_dentry_path(mdsc, rdentry, rdiri, ppath, pathlen, ino,
+-					freepath, parent_locked);
+-		doutc(cl, " dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen, *ppath);
++		r = build_dentry_path(mdsc, rdentry, rdiri, path_info, parent_locked);
++		doutc(cl, " dentry %p %llx/%.*s\n", rdentry, path_info->vino.ino,
++		      path_info->pathlen, path_info->path);
+ 	} else if (rpath || rino) {
+-		*ino = rino;
+-		*ppath = rpath;
+-		*pathlen = rpath ? strlen(rpath) : 0;
+-		doutc(cl, " path %.*s\n", *pathlen, rpath);
++		path_info->vino.ino = rino;
++		path_info->vino.snap = CEPH_NOSNAP;
++		path_info->path = rpath;
++		path_info->pathlen = rpath ? strlen(rpath) : 0;
++		path_info->freepath = false;
++
++		doutc(cl, " path %.*s\n", path_info->pathlen, rpath);
+ 	}
+ 
+ 	return r;
+@@ -2968,11 +2991,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
+ 	struct ceph_client *cl = mdsc->fsc->client;
+ 	struct ceph_msg *msg;
+ 	struct ceph_mds_request_head_legacy *lhead;
+-	const char *path1 = NULL;
+-	const char *path2 = NULL;
+-	u64 ino1 = 0, ino2 = 0;
+-	int pathlen1 = 0, pathlen2 = 0;
+-	bool freepath1 = false, freepath2 = false;
++	struct ceph_path_info path_info1 = {0};
++	struct ceph_path_info path_info2 = {0};
+ 	struct dentry *old_dentry = NULL;
+ 	int len;
+ 	u16 releases;
+@@ -2982,25 +3002,49 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
+ 	u16 request_head_version = mds_supported_head_version(session);
+ 	kuid_t caller_fsuid = req->r_cred->fsuid;
+ 	kgid_t caller_fsgid = req->r_cred->fsgid;
++	bool parent_locked = test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
+ 
+ 	ret = set_request_path_attr(mdsc, req->r_inode, req->r_dentry,
+-			      req->r_parent, req->r_path1, req->r_ino1.ino,
+-			      &path1, &pathlen1, &ino1, &freepath1,
+-			      test_bit(CEPH_MDS_R_PARENT_LOCKED,
+-					&req->r_req_flags));
++				    req->r_parent, req->r_path1, req->r_ino1.ino,
++				    &path_info1, parent_locked);
+ 	if (ret < 0) {
+ 		msg = ERR_PTR(ret);
+ 		goto out;
+ 	}
+ 
++	/*
++	 * When the parent directory's i_rwsem is *not* locked, req->r_parent may
++	 * have become stale (e.g. after a concurrent rename) between the time the
++	 * dentry was looked up and now.  If we detect that the stored r_parent
++	 * does not match the inode number we just encoded for the request, switch
++	 * to the correct inode so that the MDS receives a valid parent reference.
++	 */
++	if (!parent_locked && req->r_parent && path_info1.vino.ino &&
++	    ceph_ino(req->r_parent) != path_info1.vino.ino) {
++		struct inode *old_parent = req->r_parent;
++		struct inode *correct_dir = ceph_get_inode(mdsc->fsc->sb, path_info1.vino, NULL);
++		if (!IS_ERR(correct_dir)) {
++			WARN_ONCE(1, "ceph: r_parent mismatch (had %llx wanted %llx) - updating\n",
++			          ceph_ino(old_parent), path_info1.vino.ino);
++			/*
++			 * Transfer CEPH_CAP_PIN from the old parent to the new one.
++			 * The pin was taken earlier in ceph_mdsc_submit_request().
++			 */
++			ceph_put_cap_refs(ceph_inode(old_parent), CEPH_CAP_PIN);
++			iput(old_parent);
++			req->r_parent = correct_dir;
++			ceph_get_cap_refs(ceph_inode(req->r_parent), CEPH_CAP_PIN);
++		}
++	}
++
+ 	/* If r_old_dentry is set, then assume that its parent is locked */
+ 	if (req->r_old_dentry &&
+ 	    !(req->r_old_dentry->d_flags & DCACHE_DISCONNECTED))
+ 		old_dentry = req->r_old_dentry;
+ 	ret = set_request_path_attr(mdsc, NULL, old_dentry,
+-			      req->r_old_dentry_dir,
+-			      req->r_path2, req->r_ino2.ino,
+-			      &path2, &pathlen2, &ino2, &freepath2, true);
++				    req->r_old_dentry_dir,
++				    req->r_path2, req->r_ino2.ino,
++				    &path_info2, true);
+ 	if (ret < 0) {
+ 		msg = ERR_PTR(ret);
+ 		goto out_free1;
+@@ -3031,7 +3075,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
+ 
+ 	/* filepaths */
+ 	len += 2 * (1 + sizeof(u32) + sizeof(u64));
+-	len += pathlen1 + pathlen2;
++	len += path_info1.pathlen + path_info2.pathlen;
+ 
+ 	/* cap releases */
+ 	len += sizeof(struct ceph_mds_request_release) *
+@@ -3039,9 +3083,9 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
+ 		 !!req->r_old_inode_drop + !!req->r_old_dentry_drop);
+ 
+ 	if (req->r_dentry_drop)
+-		len += pathlen1;
++		len += path_info1.pathlen;
+ 	if (req->r_old_dentry_drop)
+-		len += pathlen2;
++		len += path_info2.pathlen;
+ 
+ 	/* MClientRequest tail */
+ 
+@@ -3154,8 +3198,8 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
+ 	lhead->ino = cpu_to_le64(req->r_deleg_ino);
+ 	lhead->args = req->r_args;
+ 
+-	ceph_encode_filepath(&p, end, ino1, path1);
+-	ceph_encode_filepath(&p, end, ino2, path2);
++	ceph_encode_filepath(&p, end, path_info1.vino.ino, path_info1.path);
++	ceph_encode_filepath(&p, end, path_info2.vino.ino, path_info2.path);
+ 
+ 	/* make note of release offset, in case we need to replay */
+ 	req->r_request_release_offset = p - msg->front.iov_base;
+@@ -3218,11 +3262,9 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
+ 	msg->hdr.data_off = cpu_to_le16(0);
+ 
+ out_free2:
+-	if (freepath2)
+-		ceph_mdsc_free_path((char *)path2, pathlen2);
++	ceph_mdsc_free_path_info(&path_info2);
+ out_free1:
+-	if (freepath1)
+-		ceph_mdsc_free_path((char *)path1, pathlen1);
++	ceph_mdsc_free_path_info(&path_info1);
+ out:
+ 	return msg;
+ out_err:
+@@ -4579,24 +4621,20 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
+ 	struct ceph_pagelist *pagelist = recon_state->pagelist;
+ 	struct dentry *dentry;
+ 	struct ceph_cap *cap;
+-	char *path;
+-	int pathlen = 0, err;
+-	u64 pathbase;
++	struct ceph_path_info path_info = {0};
++	int err;
+ 	u64 snap_follows;
+ 
+ 	dentry = d_find_primary(inode);
+ 	if (dentry) {
+ 		/* set pathbase to parent dir when msg_version >= 2 */
+-		path = ceph_mdsc_build_path(mdsc, dentry, &pathlen, &pathbase,
++		char *path = ceph_mdsc_build_path(mdsc, dentry, &path_info,
+ 					    recon_state->msg_version >= 2);
+ 		dput(dentry);
+ 		if (IS_ERR(path)) {
+ 			err = PTR_ERR(path);
+ 			goto out_err;
+ 		}
+-	} else {
+-		path = NULL;
+-		pathbase = 0;
+ 	}
+ 
+ 	spin_lock(&ci->i_ceph_lock);
+@@ -4629,7 +4667,7 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
+ 		rec.v2.wanted = cpu_to_le32(__ceph_caps_wanted(ci));
+ 		rec.v2.issued = cpu_to_le32(cap->issued);
+ 		rec.v2.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
+-		rec.v2.pathbase = cpu_to_le64(pathbase);
++		rec.v2.pathbase = cpu_to_le64(path_info.vino.ino);
+ 		rec.v2.flock_len = (__force __le32)
+ 			((ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) ? 0 : 1);
+ 	} else {
+@@ -4644,7 +4682,7 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
+ 		ts = inode_get_atime(inode);
+ 		ceph_encode_timespec64(&rec.v1.atime, &ts);
+ 		rec.v1.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
+-		rec.v1.pathbase = cpu_to_le64(pathbase);
++		rec.v1.pathbase = cpu_to_le64(path_info.vino.ino);
+ 	}
+ 
+ 	if (list_empty(&ci->i_cap_snaps)) {
+@@ -4706,7 +4744,7 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
+ 			    sizeof(struct ceph_filelock);
+ 		rec.v2.flock_len = cpu_to_le32(struct_len);
+ 
+-		struct_len += sizeof(u32) + pathlen + sizeof(rec.v2);
++		struct_len += sizeof(u32) + path_info.pathlen + sizeof(rec.v2);
+ 
+ 		if (struct_v >= 2)
+ 			struct_len += sizeof(u64); /* snap_follows */
+@@ -4730,7 +4768,7 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
+ 			ceph_pagelist_encode_8(pagelist, 1);
+ 			ceph_pagelist_encode_32(pagelist, struct_len);
+ 		}
+-		ceph_pagelist_encode_string(pagelist, path, pathlen);
++		ceph_pagelist_encode_string(pagelist, (char *)path_info.path, path_info.pathlen);
+ 		ceph_pagelist_append(pagelist, &rec, sizeof(rec.v2));
+ 		ceph_locks_to_pagelist(flocks, pagelist,
+ 				       num_fcntl_locks, num_flock_locks);
+@@ -4741,17 +4779,17 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
+ 	} else {
+ 		err = ceph_pagelist_reserve(pagelist,
+ 					    sizeof(u64) + sizeof(u32) +
+-					    pathlen + sizeof(rec.v1));
++					    path_info.pathlen + sizeof(rec.v1));
+ 		if (err)
+ 			goto out_err;
+ 
+ 		ceph_pagelist_encode_64(pagelist, ceph_ino(inode));
+-		ceph_pagelist_encode_string(pagelist, path, pathlen);
++		ceph_pagelist_encode_string(pagelist, (char *)path_info.path, path_info.pathlen);
+ 		ceph_pagelist_append(pagelist, &rec, sizeof(rec.v1));
+ 	}
+ 
+ out_err:
+-	ceph_mdsc_free_path(path, pathlen);
++	ceph_mdsc_free_path_info(&path_info);
+ 	if (!err)
+ 		recon_state->nr_caps++;
+ 	return err;
+diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
+index 3e2a6fa7c19aab..0428a5eaf28c65 100644
+--- a/fs/ceph/mds_client.h
++++ b/fs/ceph/mds_client.h
+@@ -617,14 +617,24 @@ extern int ceph_mds_check_access(struct ceph_mds_client *mdsc, char *tpath,
+ 
+ extern void ceph_mdsc_pre_umount(struct ceph_mds_client *mdsc);
+ 
+-static inline void ceph_mdsc_free_path(char *path, int len)
++/*
++ * Structure to group path-related output parameters for build_*_path functions
++ */
++struct ceph_path_info {
++	const char *path;
++	int pathlen;
++	struct ceph_vino vino;
++	bool freepath;
++};
++
++static inline void ceph_mdsc_free_path_info(const struct ceph_path_info *path_info)
+ {
+-	if (!IS_ERR_OR_NULL(path))
+-		__putname(path - (PATH_MAX - 1 - len));
++	if (path_info && path_info->freepath && !IS_ERR_OR_NULL(path_info->path))
++		__putname((char *)path_info->path - (PATH_MAX - 1 - path_info->pathlen));
+ }
+ 
+ extern char *ceph_mdsc_build_path(struct ceph_mds_client *mdsc,
+-				  struct dentry *dentry, int *plen, u64 *base,
++				  struct dentry *dentry, struct ceph_path_info *path_info,
+ 				  int for_wire);
+ 
+ extern void __ceph_mdsc_drop_dentry_lease(struct dentry *dentry);
+diff --git a/fs/coredump.c b/fs/coredump.c
+index f217ebf2b3b68f..012915262d11b7 100644
+--- a/fs/coredump.c
++++ b/fs/coredump.c
+@@ -1263,11 +1263,15 @@ static int proc_dostring_coredump(const struct ctl_table *table, int write,
+ 	ssize_t retval;
+ 	char old_core_pattern[CORENAME_MAX_SIZE];
+ 
++	if (write)
++		return proc_dostring(table, write, buffer, lenp, ppos);
++
+ 	retval = strscpy(old_core_pattern, core_pattern, CORENAME_MAX_SIZE);
+ 
+ 	error = proc_dostring(table, write, buffer, lenp, ppos);
+ 	if (error)
+ 		return error;
++
+ 	if (!check_coredump_socket()) {
+ 		strscpy(core_pattern, old_core_pattern, retval + 1);
+ 		return -EINVAL;
+diff --git a/fs/erofs/data.c b/fs/erofs/data.c
+index 16e4a6bd9b9737..dd7d86809c1881 100644
+--- a/fs/erofs/data.c
++++ b/fs/erofs/data.c
+@@ -65,10 +65,10 @@ void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb)
+ }
+ 
+ void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
+-			 erofs_off_t offset, bool need_kmap)
++			 erofs_off_t offset)
+ {
+ 	erofs_init_metabuf(buf, sb);
+-	return erofs_bread(buf, offset, need_kmap);
++	return erofs_bread(buf, offset, true);
+ }
+ 
+ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map)
+@@ -118,7 +118,7 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map)
+ 	pos = ALIGN(erofs_iloc(inode) + vi->inode_isize +
+ 		    vi->xattr_isize, unit) + unit * chunknr;
+ 
+-	idx = erofs_read_metabuf(&buf, sb, pos, true);
++	idx = erofs_read_metabuf(&buf, sb, pos);
+ 	if (IS_ERR(idx)) {
+ 		err = PTR_ERR(idx);
+ 		goto out;
+@@ -299,7 +299,7 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
+ 		struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
+ 
+ 		iomap->type = IOMAP_INLINE;
+-		ptr = erofs_read_metabuf(&buf, sb, mdev.m_pa, true);
++		ptr = erofs_read_metabuf(&buf, sb, mdev.m_pa);
+ 		if (IS_ERR(ptr))
+ 			return PTR_ERR(ptr);
+ 		iomap->inline_data = ptr;
+diff --git a/fs/erofs/fileio.c b/fs/erofs/fileio.c
+index 91781718199e2a..3ee082476c8c53 100644
+--- a/fs/erofs/fileio.c
++++ b/fs/erofs/fileio.c
+@@ -115,7 +115,7 @@ static int erofs_fileio_scan_folio(struct erofs_fileio *io, struct folio *folio)
+ 			void *src;
+ 
+ 			src = erofs_read_metabuf(&buf, inode->i_sb,
+-						 map->m_pa + ofs, true);
++						 map->m_pa + ofs);
+ 			if (IS_ERR(src)) {
+ 				err = PTR_ERR(src);
+ 				break;
+diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c
+index 34517ca9df9157..9a8ee646e51d9d 100644
+--- a/fs/erofs/fscache.c
++++ b/fs/erofs/fscache.c
+@@ -274,7 +274,7 @@ static int erofs_fscache_data_read_slice(struct erofs_fscache_rq *req)
+ 		size_t size = map.m_llen;
+ 		void *src;
+ 
+-		src = erofs_read_metabuf(&buf, sb, map.m_pa, true);
++		src = erofs_read_metabuf(&buf, sb, map.m_pa);
+ 		if (IS_ERR(src))
+ 			return PTR_ERR(src);
+ 
+diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c
+index a0ae0b4f7b012a..47215c5e33855b 100644
+--- a/fs/erofs/inode.c
++++ b/fs/erofs/inode.c
+@@ -39,10 +39,10 @@ static int erofs_read_inode(struct inode *inode)
+ 	void *ptr;
+ 	int err = 0;
+ 
+-	ptr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr), true);
++	ptr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr));
+ 	if (IS_ERR(ptr)) {
+ 		err = PTR_ERR(ptr);
+-		erofs_err(sb, "failed to get inode (nid: %llu) page, err %d",
++		erofs_err(sb, "failed to read inode meta block (nid: %llu): %d",
+ 			  vi->nid, err);
+ 		goto err_out;
+ 	}
+@@ -78,10 +78,10 @@ static int erofs_read_inode(struct inode *inode)
+ 
+ 			memcpy(&copied, dic, gotten);
+ 			ptr = erofs_read_metabuf(&buf, sb,
+-					erofs_pos(sb, blkaddr + 1), true);
++					erofs_pos(sb, blkaddr + 1));
+ 			if (IS_ERR(ptr)) {
+ 				err = PTR_ERR(ptr);
+-				erofs_err(sb, "failed to get inode payload block (nid: %llu), err %d",
++				erofs_err(sb, "failed to read inode payload block (nid: %llu): %d",
+ 					  vi->nid, err);
+ 				goto err_out;
+ 			}
+diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
+index 06b867d2fc3b7c..a7699114f6fe6d 100644
+--- a/fs/erofs/internal.h
++++ b/fs/erofs/internal.h
+@@ -385,7 +385,7 @@ void erofs_put_metabuf(struct erofs_buf *buf);
+ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap);
+ void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb);
+ void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
+-			 erofs_off_t offset, bool need_kmap);
++			 erofs_off_t offset);
+ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *dev);
+ int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+ 		 u64 start, u64 len);
+diff --git a/fs/erofs/super.c b/fs/erofs/super.c
+index cad87e4d669432..06c8981eea7f8c 100644
+--- a/fs/erofs/super.c
++++ b/fs/erofs/super.c
+@@ -141,7 +141,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
+ 	struct erofs_deviceslot *dis;
+ 	struct file *file;
+ 
+-	dis = erofs_read_metabuf(buf, sb, *pos, true);
++	dis = erofs_read_metabuf(buf, sb, *pos);
+ 	if (IS_ERR(dis))
+ 		return PTR_ERR(dis);
+ 
+@@ -268,7 +268,7 @@ static int erofs_read_superblock(struct super_block *sb)
+ 	void *data;
+ 	int ret;
+ 
+-	data = erofs_read_metabuf(&buf, sb, 0, true);
++	data = erofs_read_metabuf(&buf, sb, 0);
+ 	if (IS_ERR(data)) {
+ 		erofs_err(sb, "cannot read erofs superblock");
+ 		return PTR_ERR(data);
+@@ -999,10 +999,22 @@ static int erofs_show_options(struct seq_file *seq, struct dentry *root)
+ 	return 0;
+ }
+ 
++static void erofs_evict_inode(struct inode *inode)
++{
++#ifdef CONFIG_FS_DAX
++	if (IS_DAX(inode))
++		dax_break_layout_final(inode);
++#endif
++
++	truncate_inode_pages_final(&inode->i_data);
++	clear_inode(inode);
++}
++
+ const struct super_operations erofs_sops = {
+ 	.put_super = erofs_put_super,
+ 	.alloc_inode = erofs_alloc_inode,
+ 	.free_inode = erofs_free_inode,
++	.evict_inode = erofs_evict_inode,
+ 	.statfs = erofs_statfs,
+ 	.show_options = erofs_show_options,
+ };
+diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
+index 9bb53f00c2c629..e8f30eee29b441 100644
+--- a/fs/erofs/zdata.c
++++ b/fs/erofs/zdata.c
+@@ -805,6 +805,7 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe)
+ 	struct erofs_map_blocks *map = &fe->map;
+ 	struct super_block *sb = fe->inode->i_sb;
+ 	struct z_erofs_pcluster *pcl = NULL;
++	void *ptr;
+ 	int ret;
+ 
+ 	DBG_BUGON(fe->pcl);
+@@ -854,15 +855,14 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe)
+ 		/* bind cache first when cached decompression is preferred */
+ 		z_erofs_bind_cache(fe);
+ 	} else {
+-		void *mptr;
+-
+-		mptr = erofs_read_metabuf(&map->buf, sb, map->m_pa, false);
+-		if (IS_ERR(mptr)) {
+-			ret = PTR_ERR(mptr);
+-			erofs_err(sb, "failed to get inline data %d", ret);
++		erofs_init_metabuf(&map->buf, sb);
++		ptr = erofs_bread(&map->buf, map->m_pa, false);
++		if (IS_ERR(ptr)) {
++			ret = PTR_ERR(ptr);
++			erofs_err(sb, "failed to get inline folio %d", ret);
+ 			return ret;
+ 		}
+-		get_page(map->buf.page);
++		folio_get(page_folio(map->buf.page));
+ 		WRITE_ONCE(fe->pcl->compressed_bvecs[0].page, map->buf.page);
+ 		fe->pcl->pageofs_in = map->m_pa & ~PAGE_MASK;
+ 		fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE;
+@@ -1325,9 +1325,8 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
+ 
+ 	/* must handle all compressed pages before actual file pages */
+ 	if (pcl->from_meta) {
+-		page = pcl->compressed_bvecs[0].page;
++		folio_put(page_folio(pcl->compressed_bvecs[0].page));
+ 		WRITE_ONCE(pcl->compressed_bvecs[0].page, NULL);
+-		put_page(page);
+ 	} else {
+ 		/* managed folios are still left in compressed_bvecs[] */
+ 		for (i = 0; i < pclusterpages; ++i) {
+diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
+index f1a15ff22147ba..14d01474ad9dda 100644
+--- a/fs/erofs/zmap.c
++++ b/fs/erofs/zmap.c
+@@ -31,7 +31,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
+ 	struct z_erofs_lcluster_index *di;
+ 	unsigned int advise;
+ 
+-	di = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos, true);
++	di = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos);
+ 	if (IS_ERR(di))
+ 		return PTR_ERR(di);
+ 	m->lcn = lcn;
+@@ -146,7 +146,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m,
+ 	else
+ 		return -EOPNOTSUPP;
+ 
+-	in = erofs_read_metabuf(&m->map->buf, m->inode->i_sb, pos, true);
++	in = erofs_read_metabuf(&m->map->buf, m->inode->i_sb, pos);
+ 	if (IS_ERR(in))
+ 		return PTR_ERR(in);
+ 
+@@ -403,10 +403,10 @@ static int z_erofs_map_blocks_fo(struct inode *inode,
+ 		.inode = inode,
+ 		.map = map,
+ 	};
+-	int err = 0;
+-	unsigned int endoff, afmt;
++	unsigned int endoff;
+ 	unsigned long initial_lcn;
+ 	unsigned long long ofs, end;
++	int err;
+ 
+ 	ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? inode->i_size - 1 : map->m_la;
+ 	if (fragment && !(flags & EROFS_GET_BLOCKS_FINDTAIL) &&
+@@ -502,20 +502,15 @@ static int z_erofs_map_blocks_fo(struct inode *inode,
+ 			err = -EFSCORRUPTED;
+ 			goto unmap_out;
+ 		}
+-		afmt = vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER ?
+-			Z_EROFS_COMPRESSION_INTERLACED :
+-			Z_EROFS_COMPRESSION_SHIFTED;
++		if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER)
++			map->m_algorithmformat = Z_EROFS_COMPRESSION_INTERLACED;
++		else
++			map->m_algorithmformat = Z_EROFS_COMPRESSION_SHIFTED;
++	} else if (m.headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2) {
++		map->m_algorithmformat = vi->z_algorithmtype[1];
+ 	} else {
+-		afmt = m.headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2 ?
+-			vi->z_algorithmtype[1] : vi->z_algorithmtype[0];
+-		if (!(EROFS_I_SB(inode)->available_compr_algs & (1 << afmt))) {
+-			erofs_err(sb, "inconsistent algorithmtype %u for nid %llu",
+-				  afmt, vi->nid);
+-			err = -EFSCORRUPTED;
+-			goto unmap_out;
+-		}
++		map->m_algorithmformat = vi->z_algorithmtype[0];
+ 	}
+-	map->m_algorithmformat = afmt;
+ 
+ 	if ((flags & EROFS_GET_BLOCKS_FIEMAP) ||
+ 	    ((flags & EROFS_GET_BLOCKS_READMORE) &&
+@@ -551,7 +546,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
+ 	map->m_flags = 0;
+ 	if (recsz <= offsetof(struct z_erofs_extent, pstart_hi)) {
+ 		if (recsz <= offsetof(struct z_erofs_extent, pstart_lo)) {
+-			ext = erofs_read_metabuf(&map->buf, sb, pos, true);
++			ext = erofs_read_metabuf(&map->buf, sb, pos);
+ 			if (IS_ERR(ext))
+ 				return PTR_ERR(ext);
+ 			pa = le64_to_cpu(*(__le64 *)ext);
+@@ -564,7 +559,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
+ 		}
+ 
+ 		for (; lstart <= map->m_la; lstart += 1 << vi->z_lclusterbits) {
+-			ext = erofs_read_metabuf(&map->buf, sb, pos, true);
++			ext = erofs_read_metabuf(&map->buf, sb, pos);
+ 			if (IS_ERR(ext))
+ 				return PTR_ERR(ext);
+ 			map->m_plen = le32_to_cpu(ext->plen);
+@@ -584,7 +579,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
+ 		for (l = 0, r = vi->z_extents; l < r; ) {
+ 			mid = l + (r - l) / 2;
+ 			ext = erofs_read_metabuf(&map->buf, sb,
+-						 pos + mid * recsz, true);
++						 pos + mid * recsz);
+ 			if (IS_ERR(ext))
+ 				return PTR_ERR(ext);
+ 
+@@ -641,14 +636,13 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
+ 	return 0;
+ }
+ 
+-static int z_erofs_fill_inode_lazy(struct inode *inode)
++static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map)
+ {
+ 	struct erofs_inode *const vi = EROFS_I(inode);
+ 	struct super_block *const sb = inode->i_sb;
+-	int err, headnr;
+-	erofs_off_t pos;
+-	struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
+ 	struct z_erofs_map_header *h;
++	erofs_off_t pos;
++	int err = 0;
+ 
+ 	if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) {
+ 		/*
+@@ -662,12 +656,11 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
+ 	if (wait_on_bit_lock(&vi->flags, EROFS_I_BL_Z_BIT, TASK_KILLABLE))
+ 		return -ERESTARTSYS;
+ 
+-	err = 0;
+ 	if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags))
+ 		goto out_unlock;
+ 
+ 	pos = ALIGN(erofs_iloc(inode) + vi->inode_isize + vi->xattr_isize, 8);
+-	h = erofs_read_metabuf(&buf, sb, pos, true);
++	h = erofs_read_metabuf(&map->buf, sb, pos);
+ 	if (IS_ERR(h)) {
+ 		err = PTR_ERR(h);
+ 		goto out_unlock;
+@@ -699,22 +692,13 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
+ 	else if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER)
+ 		vi->z_idata_size = le16_to_cpu(h->h_idata_size);
+ 
+-	headnr = 0;
+-	if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX ||
+-	    vi->z_algorithmtype[++headnr] >= Z_EROFS_COMPRESSION_MAX) {
+-		erofs_err(sb, "unknown HEAD%u format %u for nid %llu, please upgrade kernel",
+-			  headnr + 1, vi->z_algorithmtype[headnr], vi->nid);
+-		err = -EOPNOTSUPP;
+-		goto out_put_metabuf;
+-	}
+-
+ 	if (!erofs_sb_has_big_pcluster(EROFS_SB(sb)) &&
+ 	    vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 |
+ 			    Z_EROFS_ADVISE_BIG_PCLUSTER_2)) {
+ 		erofs_err(sb, "per-inode big pcluster without sb feature for nid %llu",
+ 			  vi->nid);
+ 		err = -EFSCORRUPTED;
+-		goto out_put_metabuf;
++		goto out_unlock;
+ 	}
+ 	if (vi->datalayout == EROFS_INODE_COMPRESSED_COMPACT &&
+ 	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^
+@@ -722,32 +706,54 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
+ 		erofs_err(sb, "big pcluster head1/2 of compact indexes should be consistent for nid %llu",
+ 			  vi->nid);
+ 		err = -EFSCORRUPTED;
+-		goto out_put_metabuf;
++		goto out_unlock;
+ 	}
+ 
+ 	if (vi->z_idata_size ||
+ 	    (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)) {
+-		struct erofs_map_blocks map = {
++		struct erofs_map_blocks tm = {
+ 			.buf = __EROFS_BUF_INITIALIZER
+ 		};
+ 
+-		err = z_erofs_map_blocks_fo(inode, &map,
++		err = z_erofs_map_blocks_fo(inode, &tm,
+ 					    EROFS_GET_BLOCKS_FINDTAIL);
+-		erofs_put_metabuf(&map.buf);
++		erofs_put_metabuf(&tm.buf);
+ 		if (err < 0)
+-			goto out_put_metabuf;
++			goto out_unlock;
+ 	}
+ done:
+ 	/* paired with smp_mb() at the beginning of the function */
+ 	smp_mb();
+ 	set_bit(EROFS_I_Z_INITED_BIT, &vi->flags);
+-out_put_metabuf:
+-	erofs_put_metabuf(&buf);
+ out_unlock:
+ 	clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags);
+ 	return err;
+ }
+ 
++static int z_erofs_map_sanity_check(struct inode *inode,
++				    struct erofs_map_blocks *map)
++{
++	struct erofs_sb_info *sbi = EROFS_I_SB(inode);
++
++	if (!(map->m_flags & EROFS_MAP_ENCODED))
++		return 0;
++	if (unlikely(map->m_algorithmformat >= Z_EROFS_COMPRESSION_RUNTIME_MAX)) {
++		erofs_err(inode->i_sb, "unknown algorithm %d @ pos %llu for nid %llu, please upgrade kernel",
++			  map->m_algorithmformat, map->m_la, EROFS_I(inode)->nid);
++		return -EOPNOTSUPP;
++	}
++	if (unlikely(map->m_algorithmformat < Z_EROFS_COMPRESSION_MAX &&
++		     !(sbi->available_compr_algs & (1 << map->m_algorithmformat)))) {
++		erofs_err(inode->i_sb, "inconsistent algorithmtype %u for nid %llu",
++			  map->m_algorithmformat, EROFS_I(inode)->nid);
++		return -EFSCORRUPTED;
++	}
++	if (unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE ||
++		     map->m_llen > Z_EROFS_PCLUSTER_MAX_DSIZE))
++		return -EOPNOTSUPP;
++	return 0;
++}
++
+ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map,
+ 			    int flags)
+ {
+@@ -760,7 +766,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map,
+ 		map->m_la = inode->i_size;
+ 		map->m_flags = 0;
+ 	} else {
+-		err = z_erofs_fill_inode_lazy(inode);
++		err = z_erofs_fill_inode(inode, map);
+ 		if (!err) {
+ 			if (vi->datalayout == EROFS_INODE_COMPRESSED_FULL &&
+ 			    (vi->z_advise & Z_EROFS_ADVISE_EXTENTS))
+@@ -768,10 +774,8 @@ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map,
+ 			else
+ 				err = z_erofs_map_blocks_fo(inode, map, flags);
+ 		}
+-		if (!err && (map->m_flags & EROFS_MAP_ENCODED) &&
+-		    unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE ||
+-			     map->m_llen > Z_EROFS_PCLUSTER_MAX_DSIZE))
+-			err = -EOPNOTSUPP;
++		if (!err)
++			err = z_erofs_map_sanity_check(inode, map);
+ 		if (err)
+ 			map->m_llen = 0;
+ 	}
+diff --git a/fs/exec.c b/fs/exec.c
+index ba400aafd64061..551e1cc5bf1e3e 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -2048,7 +2048,7 @@ static int proc_dointvec_minmax_coredump(const struct ctl_table *table, int writ
+ {
+ 	int error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+ 
+-	if (!error)
++	if (!error && !write)
+ 		validate_coredump_safety();
+ 	return error;
+ }
+diff --git a/fs/fhandle.c b/fs/fhandle.c
+index e21ec857f2abcf..52c72896e1c164 100644
+--- a/fs/fhandle.c
++++ b/fs/fhandle.c
+@@ -202,6 +202,14 @@ static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
+ 	if (!ctx->flags)
+ 		return 1;
+ 
++	/*
++	 * Verify that the decoded dentry itself has a valid id mapping.
++	 * In case the decoded dentry is the mountfd root itself, this
++	 * verifies that the mountfd inode itself has a valid id mapping.
++	 */
++	if (!privileged_wrt_inode_uidgid(user_ns, idmap, d_inode(dentry)))
++		return 0;
++
+ 	/*
+ 	 * It's racy as we're not taking rename_lock but we're able to ignore
+ 	 * permissions and we just need an approximation whether we were able
+diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
+index e80cd8f2c049f9..5150aa25e64be9 100644
+--- a/fs/fuse/dev.c
++++ b/fs/fuse/dev.c
+@@ -1893,7 +1893,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
+ 
+ 	index = outarg->offset >> PAGE_SHIFT;
+ 
+-	while (num) {
++	while (num && ap->num_folios < num_pages) {
+ 		struct folio *folio;
+ 		unsigned int folio_offset;
+ 		unsigned int nr_bytes;
+diff --git a/fs/fuse/file.c b/fs/fuse/file.c
+index 47006d0753f1cd..b8dc8ce3e5564a 100644
+--- a/fs/fuse/file.c
++++ b/fs/fuse/file.c
+@@ -3013,7 +3013,7 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
+ 		.nodeid_out = ff_out->nodeid,
+ 		.fh_out = ff_out->fh,
+ 		.off_out = pos_out,
+-		.len = len,
++		.len = min_t(size_t, len, UINT_MAX & PAGE_MASK),
+ 		.flags = flags
+ 	};
+ 	struct fuse_write_out outarg;
+@@ -3079,6 +3079,9 @@ static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in,
+ 		fc->no_copy_file_range = 1;
+ 		err = -EOPNOTSUPP;
+ 	}
++	if (!err && outarg.size > len)
++		err = -EIO;
++
+ 	if (err)
+ 		goto out;
+ 
+diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
+index 607ef735ad4ab3..eb97ac009e75d9 100644
+--- a/fs/fuse/passthrough.c
++++ b/fs/fuse/passthrough.c
+@@ -237,6 +237,11 @@ int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
+ 	if (!file)
+ 		goto out;
+ 
++	/* read/write/splice/mmap passthrough only relevant for regular files */
++	res = d_is_dir(file->f_path.dentry) ? -EISDIR : -EINVAL;
++	if (!d_is_reg(file->f_path.dentry))
++		goto out_fput;
++
+ 	backing_sb = file_inode(file)->i_sb;
+ 	res = -ELOOP;
+ 	if (backing_sb->s_stack_depth >= fc->max_stack_depth)
+diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
+index a6c692cac61659..9adf36e6364b7d 100644
+--- a/fs/kernfs/file.c
++++ b/fs/kernfs/file.c
+@@ -70,6 +70,24 @@ static struct kernfs_open_node *of_on(struct kernfs_open_file *of)
+ 					 !list_empty(&of->list));
+ }
+ 
++/* Get active reference to kernfs node for an open file */
++static struct kernfs_open_file *kernfs_get_active_of(struct kernfs_open_file *of)
++{
++	/* Skip if file was already released */
++	if (unlikely(of->released))
++		return NULL;
++
++	if (!kernfs_get_active(of->kn))
++		return NULL;
++
++	return of;
++}
++
++static void kernfs_put_active_of(struct kernfs_open_file *of)
++{
++	return kernfs_put_active(of->kn);
++}
++
+ /**
+  * kernfs_deref_open_node_locked - Get kernfs_open_node corresponding to @kn
+  *
+@@ -139,7 +157,7 @@ static void kernfs_seq_stop_active(struct seq_file *sf, void *v)
+ 
+ 	if (ops->seq_stop)
+ 		ops->seq_stop(sf, v);
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ }
+ 
+ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos)
+@@ -152,7 +170,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos)
+ 	 * the ops aren't called concurrently for the same open file.
+ 	 */
+ 	mutex_lock(&of->mutex);
+-	if (!kernfs_get_active(of->kn))
++	if (!kernfs_get_active_of(of))
+ 		return ERR_PTR(-ENODEV);
+ 
+ 	ops = kernfs_ops(of->kn);
+@@ -238,7 +256,7 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+ 	 * the ops aren't called concurrently for the same open file.
+ 	 */
+ 	mutex_lock(&of->mutex);
+-	if (!kernfs_get_active(of->kn)) {
++	if (!kernfs_get_active_of(of)) {
+ 		len = -ENODEV;
+ 		mutex_unlock(&of->mutex);
+ 		goto out_free;
+@@ -252,7 +270,7 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+ 	else
+ 		len = -EINVAL;
+ 
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ 	mutex_unlock(&of->mutex);
+ 
+ 	if (len < 0)
+@@ -323,7 +341,7 @@ static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+ 	 * the ops aren't called concurrently for the same open file.
+ 	 */
+ 	mutex_lock(&of->mutex);
+-	if (!kernfs_get_active(of->kn)) {
++	if (!kernfs_get_active_of(of)) {
+ 		mutex_unlock(&of->mutex);
+ 		len = -ENODEV;
+ 		goto out_free;
+@@ -335,7 +353,7 @@ static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+ 	else
+ 		len = -EINVAL;
+ 
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ 	mutex_unlock(&of->mutex);
+ 
+ 	if (len > 0)
+@@ -357,13 +375,13 @@ static void kernfs_vma_open(struct vm_area_struct *vma)
+ 	if (!of->vm_ops)
+ 		return;
+ 
+-	if (!kernfs_get_active(of->kn))
++	if (!kernfs_get_active_of(of))
+ 		return;
+ 
+ 	if (of->vm_ops->open)
+ 		of->vm_ops->open(vma);
+ 
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ }
+ 
+ static vm_fault_t kernfs_vma_fault(struct vm_fault *vmf)
+@@ -375,14 +393,14 @@ static vm_fault_t kernfs_vma_fault(struct vm_fault *vmf)
+ 	if (!of->vm_ops)
+ 		return VM_FAULT_SIGBUS;
+ 
+-	if (!kernfs_get_active(of->kn))
++	if (!kernfs_get_active_of(of))
+ 		return VM_FAULT_SIGBUS;
+ 
+ 	ret = VM_FAULT_SIGBUS;
+ 	if (of->vm_ops->fault)
+ 		ret = of->vm_ops->fault(vmf);
+ 
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ 	return ret;
+ }
+ 
+@@ -395,7 +413,7 @@ static vm_fault_t kernfs_vma_page_mkwrite(struct vm_fault *vmf)
+ 	if (!of->vm_ops)
+ 		return VM_FAULT_SIGBUS;
+ 
+-	if (!kernfs_get_active(of->kn))
++	if (!kernfs_get_active_of(of))
+ 		return VM_FAULT_SIGBUS;
+ 
+ 	ret = 0;
+@@ -404,7 +422,7 @@ static vm_fault_t kernfs_vma_page_mkwrite(struct vm_fault *vmf)
+ 	else
+ 		file_update_time(file);
+ 
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ 	return ret;
+ }
+ 
+@@ -418,14 +436,14 @@ static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr,
+ 	if (!of->vm_ops)
+ 		return -EINVAL;
+ 
+-	if (!kernfs_get_active(of->kn))
++	if (!kernfs_get_active_of(of))
+ 		return -EINVAL;
+ 
+ 	ret = -EINVAL;
+ 	if (of->vm_ops->access)
+ 		ret = of->vm_ops->access(vma, addr, buf, len, write);
+ 
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ 	return ret;
+ }
+ 
+@@ -455,7 +473,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma)
+ 	mutex_lock(&of->mutex);
+ 
+ 	rc = -ENODEV;
+-	if (!kernfs_get_active(of->kn))
++	if (!kernfs_get_active_of(of))
+ 		goto out_unlock;
+ 
+ 	ops = kernfs_ops(of->kn);
+@@ -490,7 +508,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma)
+ 	}
+ 	vma->vm_ops = &kernfs_vm_ops;
+ out_put:
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ out_unlock:
+ 	mutex_unlock(&of->mutex);
+ 
+@@ -852,7 +870,7 @@ static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait)
+ 	struct kernfs_node *kn = kernfs_dentry_node(filp->f_path.dentry);
+ 	__poll_t ret;
+ 
+-	if (!kernfs_get_active(kn))
++	if (!kernfs_get_active_of(of))
+ 		return DEFAULT_POLLMASK|EPOLLERR|EPOLLPRI;
+ 
+ 	if (kn->attr.ops->poll)
+@@ -860,7 +878,7 @@ static __poll_t kernfs_fop_poll(struct file *filp, poll_table *wait)
+ 	else
+ 		ret = kernfs_generic_poll(of, wait);
+ 
+-	kernfs_put_active(kn);
++	kernfs_put_active_of(of);
+ 	return ret;
+ }
+ 
+@@ -875,7 +893,7 @@ static loff_t kernfs_fop_llseek(struct file *file, loff_t offset, int whence)
+ 	 * the ops aren't called concurrently for the same open file.
+ 	 */
+ 	mutex_lock(&of->mutex);
+-	if (!kernfs_get_active(of->kn)) {
++	if (!kernfs_get_active_of(of)) {
+ 		mutex_unlock(&of->mutex);
+ 		return -ENODEV;
+ 	}
+@@ -886,7 +904,7 @@ static loff_t kernfs_fop_llseek(struct file *file, loff_t offset, int whence)
+ 	else
+ 		ret = generic_file_llseek(file, offset, whence);
+ 
+-	kernfs_put_active(of->kn);
++	kernfs_put_active_of(of);
+ 	mutex_unlock(&of->mutex);
+ 	return ret;
+ }
+diff --git a/fs/nfs/client.c b/fs/nfs/client.c
+index 3bcf5c204578c1..97bd9d2a4b0cde 100644
+--- a/fs/nfs/client.c
++++ b/fs/nfs/client.c
+@@ -890,6 +890,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
+ 
+ 	if (fsinfo->xattr_support)
+ 		server->caps |= NFS_CAP_XATTR;
++	else
++		server->caps &= ~NFS_CAP_XATTR;
+ #endif
+ }
+ 
+diff --git a/fs/nfs/file.c b/fs/nfs/file.c
+index 033feeab8c346e..a16a619fb8c33b 100644
+--- a/fs/nfs/file.c
++++ b/fs/nfs/file.c
+@@ -437,10 +437,11 @@ static void nfs_invalidate_folio(struct folio *folio, size_t offset,
+ 	dfprintk(PAGECACHE, "NFS: invalidate_folio(%lu, %zu, %zu)\n",
+ 		 folio->index, offset, length);
+ 
+-	if (offset != 0 || length < folio_size(folio))
+-		return;
+ 	/* Cancel any unstarted writes on this page */
+-	nfs_wb_folio_cancel(inode, folio);
++	if (offset != 0 || length < folio_size(folio))
++		nfs_wb_folio(inode, folio);
++	else
++		nfs_wb_folio_cancel(inode, folio);
+ 	folio_wait_private_2(folio); /* [DEPRECATED] */
+ 	trace_nfs_invalidate_folio(inode, folio_pos(folio) + offset, length);
+ }
+diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
+index 8dc921d835388e..9edb5f9b0c4e47 100644
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -293,7 +293,7 @@ ff_lseg_match_mirrors(struct pnfs_layout_segment *l1,
+ 		struct pnfs_layout_segment *l2)
+ {
+ 	const struct nfs4_ff_layout_segment *fl1 = FF_LAYOUT_LSEG(l1);
+-	const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l1);
++	const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l2);
+ 	u32 i;
+ 
+ 	if (fl1->mirror_array_cnt != fl2->mirror_array_cnt)
+@@ -773,8 +773,11 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
+ 			continue;
+ 
+ 		if (check_device &&
+-		    nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node))
++		    nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node)) {
++			// reinitialize the error state in case if this is the last iteration
++			ds = ERR_PTR(-EINVAL);
+ 			continue;
++		}
+ 
+ 		*best_idx = idx;
+ 		break;
+@@ -804,7 +807,7 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
+ 	struct nfs4_pnfs_ds *ds;
+ 
+ 	ds = ff_layout_choose_valid_ds_for_read(lseg, start_idx, best_idx);
+-	if (ds)
++	if (!IS_ERR(ds))
+ 		return ds;
+ 	return ff_layout_choose_any_ds_for_read(lseg, start_idx, best_idx);
+ }
+@@ -818,7 +821,7 @@ ff_layout_get_ds_for_read(struct nfs_pageio_descriptor *pgio,
+ 
+ 	ds = ff_layout_choose_best_ds_for_read(lseg, pgio->pg_mirror_idx,
+ 					       best_idx);
+-	if (ds || !pgio->pg_mirror_idx)
++	if (!IS_ERR(ds) || !pgio->pg_mirror_idx)
+ 		return ds;
+ 	return ff_layout_choose_best_ds_for_read(lseg, 0, best_idx);
+ }
+@@ -868,7 +871,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
+ 	req->wb_nio = 0;
+ 
+ 	ds = ff_layout_get_ds_for_read(pgio, &ds_idx);
+-	if (!ds) {
++	if (IS_ERR(ds)) {
+ 		if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
+ 			goto out_mds;
+ 		pnfs_generic_pg_cleanup(pgio);
+@@ -1072,11 +1075,13 @@ static void ff_layout_resend_pnfs_read(struct nfs_pgio_header *hdr)
+ {
+ 	u32 idx = hdr->pgio_mirror_idx + 1;
+ 	u32 new_idx = 0;
++	struct nfs4_pnfs_ds *ds;
+ 
+-	if (ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx))
+-		ff_layout_send_layouterror(hdr->lseg);
+-	else
++	ds = ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx);
++	if (IS_ERR(ds))
+ 		pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg);
++	else
++		ff_layout_send_layouterror(hdr->lseg);
+ 	pnfs_read_resend_pnfs(hdr, new_idx);
+ }
+ 
+diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
+index a2fa6bc4d74e37..a32cc45425e287 100644
+--- a/fs/nfs/inode.c
++++ b/fs/nfs/inode.c
+@@ -761,8 +761,10 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ 	trace_nfs_setattr_enter(inode);
+ 
+ 	/* Write all dirty data */
+-	if (S_ISREG(inode->i_mode))
++	if (S_ISREG(inode->i_mode)) {
++		nfs_file_block_o_direct(NFS_I(inode));
+ 		nfs_sync_inode(inode);
++	}
+ 
+ 	fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode));
+ 	if (fattr == NULL) {
+diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
+index 9dcbc339649221..0ef0fc6aba3b3c 100644
+--- a/fs/nfs/internal.h
++++ b/fs/nfs/internal.h
+@@ -531,6 +531,16 @@ static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)
+ 	return test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0;
+ }
+ 
++/* Must be called with exclusively locked inode->i_rwsem */
++static inline void nfs_file_block_o_direct(struct nfs_inode *nfsi)
++{
++	if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
++		clear_bit(NFS_INO_ODIRECT, &nfsi->flags);
++		inode_dio_wait(&nfsi->vfs_inode);
++	}
++}
++
++
+ /* namespace.c */
+ #define NFS_PATH_CANONICAL 1
+ extern char *nfs_path(char **p, struct dentry *dentry,
+diff --git a/fs/nfs/io.c b/fs/nfs/io.c
+index 3388faf2acb9f5..d275b0a250bf3b 100644
+--- a/fs/nfs/io.c
++++ b/fs/nfs/io.c
+@@ -14,15 +14,6 @@
+ 
+ #include "internal.h"
+ 
+-/* Call with exclusively locked inode->i_rwsem */
+-static void nfs_block_o_direct(struct nfs_inode *nfsi, struct inode *inode)
+-{
+-	if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
+-		clear_bit(NFS_INO_ODIRECT, &nfsi->flags);
+-		inode_dio_wait(inode);
+-	}
+-}
+-
+ /**
+  * nfs_start_io_read - declare the file is being used for buffered reads
+  * @inode: file inode
+@@ -57,7 +48,7 @@ nfs_start_io_read(struct inode *inode)
+ 	err = down_write_killable(&inode->i_rwsem);
+ 	if (err)
+ 		return err;
+-	nfs_block_o_direct(nfsi, inode);
++	nfs_file_block_o_direct(nfsi);
+ 	downgrade_write(&inode->i_rwsem);
+ 
+ 	return 0;
+@@ -90,7 +81,7 @@ nfs_start_io_write(struct inode *inode)
+ 
+ 	err = down_write_killable(&inode->i_rwsem);
+ 	if (!err)
+-		nfs_block_o_direct(NFS_I(inode), inode);
++		nfs_file_block_o_direct(NFS_I(inode));
+ 	return err;
+ }
+ 
+diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c
+index 510d0a16cfe917..e2213ef18baede 100644
+--- a/fs/nfs/localio.c
++++ b/fs/nfs/localio.c
+@@ -453,12 +453,13 @@ static void nfs_local_call_read(struct work_struct *work)
+ 	nfs_local_iter_init(&iter, iocb, READ);
+ 
+ 	status = filp->f_op->read_iter(&iocb->kiocb, &iter);
++
++	revert_creds(save_cred);
++
+ 	if (status != -EIOCBQUEUED) {
+ 		nfs_local_read_done(iocb, status);
+ 		nfs_local_pgio_release(iocb);
+ 	}
+-
+-	revert_creds(save_cred);
+ }
+ 
+ static int
+@@ -649,14 +650,15 @@ static void nfs_local_call_write(struct work_struct *work)
+ 	file_start_write(filp);
+ 	status = filp->f_op->write_iter(&iocb->kiocb, &iter);
+ 	file_end_write(filp);
++
++	revert_creds(save_cred);
++	current->flags = old_flags;
++
+ 	if (status != -EIOCBQUEUED) {
+ 		nfs_local_write_done(iocb, status);
+ 		nfs_local_vfs_getattr(iocb);
+ 		nfs_local_pgio_release(iocb);
+ 	}
+-
+-	revert_creds(save_cred);
+-	current->flags = old_flags;
+ }
+ 
+ static int
+diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
+index 01c01f45358b7c..48ee3d5d89c4ae 100644
+--- a/fs/nfs/nfs42proc.c
++++ b/fs/nfs/nfs42proc.c
+@@ -114,6 +114,7 @@ static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
+ 	exception.inode = inode;
+ 	exception.state = lock->open_context->state;
+ 
++	nfs_file_block_o_direct(NFS_I(inode));
+ 	err = nfs_sync_inode(inode);
+ 	if (err)
+ 		goto out;
+@@ -430,6 +431,7 @@ static ssize_t _nfs42_proc_copy(struct file *src,
+ 		return status;
+ 	}
+ 
++	nfs_file_block_o_direct(NFS_I(dst_inode));
+ 	status = nfs_sync_inode(dst_inode);
+ 	if (status)
+ 		return status;
+diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
+index 5e9d66f3466c8d..1fa69a0b33ab19 100644
+--- a/fs/nfs/nfs4file.c
++++ b/fs/nfs/nfs4file.c
+@@ -291,9 +291,11 @@ static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
+ 
+ 	/* flush all pending writes on both src and dst so that server
+ 	 * has the latest data */
++	nfs_file_block_o_direct(NFS_I(src_inode));
+ 	ret = nfs_sync_inode(src_inode);
+ 	if (ret)
+ 		goto out_unlock;
++	nfs_file_block_o_direct(NFS_I(dst_inode));
+ 	ret = nfs_sync_inode(dst_inode);
+ 	if (ret)
+ 		goto out_unlock;
+diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
+index 7e203857f46687..8d492e3b216312 100644
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -4007,8 +4007,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
+ 				     res.attr_bitmask[2];
+ 		}
+ 		memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
+-		server->caps &= ~(NFS_CAP_ACLS | NFS_CAP_HARDLINKS |
+-				  NFS_CAP_SYMLINKS| NFS_CAP_SECURITY_LABEL);
++		server->caps &=
++			~(NFS_CAP_ACLS | NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS |
++			  NFS_CAP_SECURITY_LABEL | NFS_CAP_FS_LOCATIONS |
++			  NFS_CAP_OPEN_XOR | NFS_CAP_DELEGTIME);
+ 		server->fattr_valid = NFS_ATTR_FATTR_V4;
+ 		if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
+ 				res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
+@@ -4082,7 +4084,6 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
+ 	};
+ 	int err;
+ 
+-	nfs_server_set_init_caps(server);
+ 	do {
+ 		err = nfs4_handle_exception(server,
+ 				_nfs4_server_capabilities(server, fhandle),
+diff --git a/fs/nfs/write.c b/fs/nfs/write.c
+index ff29335ed85999..08fd1c0d45ec27 100644
+--- a/fs/nfs/write.c
++++ b/fs/nfs/write.c
+@@ -2045,6 +2045,7 @@ int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio)
+ 		 * release it */
+ 		nfs_inode_remove_request(req);
+ 		nfs_unlock_and_release_request(req);
++		folio_cancel_dirty(folio);
+ 	}
+ 
+ 	return ret;
+diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
+index 930150ed5db15f..ef147e8b327126 100644
+--- a/fs/ocfs2/extent_map.c
++++ b/fs/ocfs2/extent_map.c
+@@ -706,6 +706,8 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
+  * it not only handles the fiemap for inlined files, but also deals
+  * with the fast symlink, cause they have no difference for extent
+  * mapping per se.
++ *
++ * Must be called with ip_alloc_sem semaphore held.
+  */
+ static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh,
+ 			       struct fiemap_extent_info *fieinfo,
+@@ -717,6 +719,7 @@ static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh,
+ 	u64 phys;
+ 	u32 flags = FIEMAP_EXTENT_DATA_INLINE|FIEMAP_EXTENT_LAST;
+ 	struct ocfs2_inode_info *oi = OCFS2_I(inode);
++	lockdep_assert_held_read(&oi->ip_alloc_sem);
+ 
+ 	di = (struct ocfs2_dinode *)di_bh->b_data;
+ 	if (ocfs2_inode_is_fast_symlink(inode))
+@@ -732,8 +735,11 @@ static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh,
+ 			phys += offsetof(struct ocfs2_dinode,
+ 					 id2.i_data.id_data);
+ 
++		/* Release the ip_alloc_sem to prevent deadlock on page fault */
++		up_read(&OCFS2_I(inode)->ip_alloc_sem);
+ 		ret = fiemap_fill_next_extent(fieinfo, 0, phys, id_count,
+ 					      flags);
++		down_read(&OCFS2_I(inode)->ip_alloc_sem);
+ 		if (ret < 0)
+ 			return ret;
+ 	}
+@@ -802,9 +808,11 @@ int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+ 		len_bytes = (u64)le16_to_cpu(rec.e_leaf_clusters) << osb->s_clustersize_bits;
+ 		phys_bytes = le64_to_cpu(rec.e_blkno) << osb->sb->s_blocksize_bits;
+ 		virt_bytes = (u64)le32_to_cpu(rec.e_cpos) << osb->s_clustersize_bits;
+-
++		/* Release the ip_alloc_sem to prevent deadlock on page fault */
++		up_read(&OCFS2_I(inode)->ip_alloc_sem);
+ 		ret = fiemap_fill_next_extent(fieinfo, virt_bytes, phys_bytes,
+ 					      len_bytes, fe_flags);
++		down_read(&OCFS2_I(inode)->ip_alloc_sem);
+ 		if (ret)
+ 			break;
+ 
+diff --git a/fs/proc/generic.c b/fs/proc/generic.c
+index 409bc1d11eca39..8e1e48760ffe05 100644
+--- a/fs/proc/generic.c
++++ b/fs/proc/generic.c
+@@ -390,7 +390,8 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir,
+ 	if (proc_alloc_inum(&dp->low_ino))
+ 		goto out_free_entry;
+ 
+-	pde_set_flags(dp);
++	if (!S_ISDIR(dp->mode))
++		pde_set_flags(dp);
+ 
+ 	write_lock(&proc_subdir_lock);
+ 	dp->parent = dir;
+diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
+index d98e0d2de09fd0..3c39cfacb25183 100644
+--- a/fs/resctrl/ctrlmondata.c
++++ b/fs/resctrl/ctrlmondata.c
+@@ -625,11 +625,11 @@ int rdtgroup_mondata_show(struct seq_file *m, void *arg)
+ 		 */
+ 		list_for_each_entry(d, &r->mon_domains, hdr.list) {
+ 			if (d->ci_id == domid) {
+-				rr.ci_id = d->ci_id;
+ 				cpu = cpumask_any(&d->hdr.cpu_mask);
+ 				ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE);
+ 				if (!ci)
+ 					continue;
++				rr.ci = ci;
+ 				mon_event_read(&rr, r, NULL, rdtgrp,
+ 					       &ci->shared_cpu_map, evtid, false);
+ 				goto checkresult;
+diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
+index 0a1eedba2b03ad..9a8cf6f11151d9 100644
+--- a/fs/resctrl/internal.h
++++ b/fs/resctrl/internal.h
+@@ -98,7 +98,7 @@ struct mon_data {
+  *	   domains in @r sharing L3 @ci.id
+  * @evtid: Which monitor event to read.
+  * @first: Initialize MBM counter when true.
+- * @ci_id: Cacheinfo id for L3. Only set when @d is NULL. Used when summing domains.
++ * @ci:    Cacheinfo for L3. Only set when @d is NULL. Used when summing domains.
+  * @err:   Error encountered when reading counter.
+  * @val:   Returned value of event counter. If @rgrp is a parent resource group,
+  *	   @val includes the sum of event counts from its child resource groups.
+@@ -112,7 +112,7 @@ struct rmid_read {
+ 	struct rdt_mon_domain	*d;
+ 	enum resctrl_event_id	evtid;
+ 	bool			first;
+-	unsigned int		ci_id;
++	struct cacheinfo	*ci;
+ 	int			err;
+ 	u64			val;
+ 	void			*arch_mon_ctx;
+diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c
+index f5637855c3acac..7326c28a7908f3 100644
+--- a/fs/resctrl/monitor.c
++++ b/fs/resctrl/monitor.c
+@@ -361,7 +361,6 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
+ {
+ 	int cpu = smp_processor_id();
+ 	struct rdt_mon_domain *d;
+-	struct cacheinfo *ci;
+ 	struct mbm_state *m;
+ 	int err, ret;
+ 	u64 tval = 0;
+@@ -389,8 +388,7 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
+ 	}
+ 
+ 	/* Summing domains that share a cache, must be on a CPU for that cache. */
+-	ci = get_cpu_cacheinfo_level(cpu, RESCTRL_L3_CACHE);
+-	if (!ci || ci->id != rr->ci_id)
++	if (!cpumask_test_cpu(cpu, &rr->ci->shared_cpu_map))
+ 		return -EINVAL;
+ 
+ 	/*
+@@ -402,7 +400,7 @@ static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
+ 	 */
+ 	ret = -EINVAL;
+ 	list_for_each_entry(d, &rr->r->mon_domains, hdr.list) {
+-		if (d->ci_id != rr->ci_id)
++		if (d->ci_id != rr->ci->id)
+ 			continue;
+ 		err = resctrl_arch_rmid_read(rr->r, d, closid, rmid,
+ 					     rr->evtid, &tval, rr->arch_mon_ctx);
+diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
+index 89160bc34d3539..4aaa9e8d9cbeff 100644
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -87,7 +87,7 @@
+ #define SMB_INTERFACE_POLL_INTERVAL	600
+ 
+ /* maximum number of PDUs in one compound */
+-#define MAX_COMPOUND 7
++#define MAX_COMPOUND 10
+ 
+ /*
+  * Default number of credits to keep available for SMB3.
+@@ -1877,9 +1877,12 @@ static inline bool is_replayable_error(int error)
+ 
+ 
+ /* cifs_get_writable_file() flags */
+-#define FIND_WR_ANY         0
+-#define FIND_WR_FSUID_ONLY  1
+-#define FIND_WR_WITH_DELETE 2
++enum cifs_writable_file_flags {
++	FIND_WR_ANY			= 0U,
++	FIND_WR_FSUID_ONLY		= (1U << 0),
++	FIND_WR_WITH_DELETE		= (1U << 1),
++	FIND_WR_NO_PENDING_DELETE	= (1U << 2),
++};
+ 
+ #define   MID_FREE 0
+ #define   MID_REQUEST_ALLOCATED 1
+@@ -2339,6 +2342,8 @@ struct smb2_compound_vars {
+ 	struct kvec qi_iov;
+ 	struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
+ 	struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
++	struct kvec unlink_iov[SMB2_SET_INFO_IOV_SIZE];
++	struct kvec rename_iov[SMB2_SET_INFO_IOV_SIZE];
+ 	struct kvec close_iov;
+ 	struct smb2_file_rename_info_hdr rename_info;
+ 	struct smb2_file_link_info_hdr link_info;
+diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
+index 1421bde045c21d..8b407d2a8516d1 100644
+--- a/fs/smb/client/file.c
++++ b/fs/smb/client/file.c
+@@ -998,7 +998,10 @@ int cifs_open(struct inode *inode, struct file *file)
+ 
+ 	/* Get the cached handle as SMB2 close is deferred */
+ 	if (OPEN_FMODE(file->f_flags) & FMODE_WRITE) {
+-		rc = cifs_get_writable_path(tcon, full_path, FIND_WR_FSUID_ONLY, &cfile);
++		rc = cifs_get_writable_path(tcon, full_path,
++					    FIND_WR_FSUID_ONLY |
++					    FIND_WR_NO_PENDING_DELETE,
++					    &cfile);
+ 	} else {
+ 		rc = cifs_get_readable_path(tcon, full_path, &cfile);
+ 	}
+@@ -2530,6 +2533,9 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
+ 			continue;
+ 		if (with_delete && !(open_file->fid.access & DELETE))
+ 			continue;
++		if ((flags & FIND_WR_NO_PENDING_DELETE) &&
++		    open_file->status_file_deleted)
++			continue;
+ 		if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
+ 			if (!open_file->invalidHandle) {
+ 				/* found a good writable file */
+@@ -2647,6 +2653,16 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
+ 		spin_unlock(&tcon->open_file_lock);
+ 		free_dentry_path(page);
+ 		*ret_file = find_readable_file(cinode, 0);
++		if (*ret_file) {
++			spin_lock(&cinode->open_file_lock);
++			if ((*ret_file)->status_file_deleted) {
++				spin_unlock(&cinode->open_file_lock);
++				cifsFileInfo_put(*ret_file);
++				*ret_file = NULL;
++			} else {
++				spin_unlock(&cinode->open_file_lock);
++			}
++		}
+ 		return *ret_file ? 0 : -ENOENT;
+ 	}
+ 
+diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
+index fe453a4b3dc831..11d442e8b3d622 100644
+--- a/fs/smb/client/inode.c
++++ b/fs/smb/client/inode.c
+@@ -1931,7 +1931,7 @@ cifs_drop_nlink(struct inode *inode)
+  * but will return the EACCES to the caller. Note that the VFS does not call
+  * unlink on negative dentries currently.
+  */
+-int cifs_unlink(struct inode *dir, struct dentry *dentry)
++static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyrename)
+ {
+ 	int rc = 0;
+ 	unsigned int xid;
+@@ -2003,7 +2003,11 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
+ 		goto psx_del_no_retry;
+ 	}
+ 
+-	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry);
++	if (sillyrename || (server->vals->protocol_id > SMB10_PROT_ID &&
++			    d_is_positive(dentry) && d_count(dentry) > 2))
++		rc = -EBUSY;
++	else
++		rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry);
+ 
+ psx_del_no_retry:
+ 	if (!rc) {
+@@ -2071,6 +2075,11 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
+ 	return rc;
+ }
+ 
++int cifs_unlink(struct inode *dir, struct dentry *dentry)
++{
++	return __cifs_unlink(dir, dentry, false);
++}
++
+ static int
+ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
+ 		 const char *full_path, struct cifs_sb_info *cifs_sb,
+@@ -2358,14 +2367,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
+ 	rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
+ 	cifs_put_tlink(tlink);
+ 
++	cifsInode = CIFS_I(d_inode(direntry));
++
+ 	if (!rc) {
++		set_bit(CIFS_INO_DELETE_PENDING, &cifsInode->flags);
+ 		spin_lock(&d_inode(direntry)->i_lock);
+ 		i_size_write(d_inode(direntry), 0);
+ 		clear_nlink(d_inode(direntry));
+ 		spin_unlock(&d_inode(direntry)->i_lock);
+ 	}
+ 
+-	cifsInode = CIFS_I(d_inode(direntry));
+ 	/* force revalidate to go get info when needed */
+ 	cifsInode->time = 0;
+ 
+@@ -2458,8 +2469,11 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
+ 	}
+ #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+ do_rename_exit:
+-	if (rc == 0)
++	if (rc == 0) {
+ 		d_move(from_dentry, to_dentry);
++		/* Force a new lookup */
++		d_drop(from_dentry);
++	}
+ 	cifs_put_tlink(tlink);
+ 	return rc;
+ }
+@@ -2470,6 +2484,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
+ 	     struct dentry *target_dentry, unsigned int flags)
+ {
+ 	const char *from_name, *to_name;
++	struct TCP_Server_Info *server;
+ 	void *page1, *page2;
+ 	struct cifs_sb_info *cifs_sb;
+ 	struct tcon_link *tlink;
+@@ -2505,6 +2520,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
+ 	if (IS_ERR(tlink))
+ 		return PTR_ERR(tlink);
+ 	tcon = tlink_tcon(tlink);
++	server = tcon->ses->server;
+ 
+ 	page1 = alloc_dentry_path();
+ 	page2 = alloc_dentry_path();
+@@ -2591,19 +2607,53 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
+ 
+ unlink_target:
+ #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+-
+-	/* Try unlinking the target dentry if it's not negative */
+-	if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) {
+-		if (d_is_dir(target_dentry))
+-			tmprc = cifs_rmdir(target_dir, target_dentry);
+-		else
+-			tmprc = cifs_unlink(target_dir, target_dentry);
+-		if (tmprc)
+-			goto cifs_rename_exit;
+-		rc = cifs_do_rename(xid, source_dentry, from_name,
+-				    target_dentry, to_name);
+-		if (!rc)
+-			rehash = false;
++	if (d_really_is_positive(target_dentry)) {
++		if (!rc) {
++			struct inode *inode = d_inode(target_dentry);
++			/*
++			 * Samba and ksmbd servers allow renaming a target
++			 * directory that is open, so make sure to update
++			 * ->i_nlink and then mark it as delete pending.
++			 */
++			if (S_ISDIR(inode->i_mode)) {
++				drop_cached_dir_by_name(xid, tcon, to_name, cifs_sb);
++				spin_lock(&inode->i_lock);
++				i_size_write(inode, 0);
++				clear_nlink(inode);
++				spin_unlock(&inode->i_lock);
++				set_bit(CIFS_INO_DELETE_PENDING, &CIFS_I(inode)->flags);
++				CIFS_I(inode)->time = 0; /* force reval */
++				inode_set_ctime_current(inode);
++				inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
++			}
++		} else if (rc == -EACCES || rc == -EEXIST) {
++			/*
++			 * Rename failed, possibly due to a busy target.
++			 * Retry it by unliking the target first.
++			 */
++			if (d_is_dir(target_dentry)) {
++				tmprc = cifs_rmdir(target_dir, target_dentry);
++			} else {
++				tmprc = __cifs_unlink(target_dir, target_dentry,
++						      server->vals->protocol_id > SMB10_PROT_ID);
++			}
++			if (tmprc) {
++				/*
++				 * Some servers will return STATUS_ACCESS_DENIED
++				 * or STATUS_DIRECTORY_NOT_EMPTY when failing to
++				 * rename a non-empty directory.  Make sure to
++				 * propagate the appropriate error back to
++				 * userspace.
++				 */
++				if (tmprc == -EEXIST || tmprc == -ENOTEMPTY)
++					rc = tmprc;
++				goto cifs_rename_exit;
++			}
++			rc = cifs_do_rename(xid, source_dentry, from_name,
++					    target_dentry, to_name);
++			if (!rc)
++				rehash = false;
++		}
+ 	}
+ 
+ 	/* force revalidate to go get info when needed */
+@@ -2629,6 +2679,8 @@ cifs_dentry_needs_reval(struct dentry *dentry)
+ 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+ 	struct cached_fid *cfid = NULL;
+ 
++	if (test_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags))
++		return false;
+ 	if (cifs_i->time == 0)
+ 		return true;
+ 
+diff --git a/fs/smb/client/smb2glob.h b/fs/smb/client/smb2glob.h
+index 224495322a05da..e56e4d402f1382 100644
+--- a/fs/smb/client/smb2glob.h
++++ b/fs/smb/client/smb2glob.h
+@@ -30,10 +30,9 @@ enum smb2_compound_ops {
+ 	SMB2_OP_QUERY_DIR,
+ 	SMB2_OP_MKDIR,
+ 	SMB2_OP_RENAME,
+-	SMB2_OP_DELETE,
+ 	SMB2_OP_HARDLINK,
+ 	SMB2_OP_SET_EOF,
+-	SMB2_OP_RMDIR,
++	SMB2_OP_UNLINK,
+ 	SMB2_OP_POSIX_QUERY_INFO,
+ 	SMB2_OP_SET_REPARSE,
+ 	SMB2_OP_GET_REPARSE,
+diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
+index 8b271bbe41c471..86cad8ee8e6f3b 100644
+--- a/fs/smb/client/smb2inode.c
++++ b/fs/smb/client/smb2inode.c
+@@ -346,9 +346,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ 			trace_smb3_posix_query_info_compound_enter(xid, tcon->tid,
+ 								   ses->Suid, full_path);
+ 			break;
+-		case SMB2_OP_DELETE:
+-			trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, full_path);
+-			break;
+ 		case SMB2_OP_MKDIR:
+ 			/*
+ 			 * Directories are created through parameters in the
+@@ -356,23 +353,40 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ 			 */
+ 			trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, full_path);
+ 			break;
+-		case SMB2_OP_RMDIR:
+-			rqst[num_rqst].rq_iov = &vars->si_iov[0];
++		case SMB2_OP_UNLINK:
++			rqst[num_rqst].rq_iov = vars->unlink_iov;
+ 			rqst[num_rqst].rq_nvec = 1;
+ 
+ 			size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
+ 			data[0] = &delete_pending[0];
+ 
+-			rc = SMB2_set_info_init(tcon, server,
+-						&rqst[num_rqst], COMPOUND_FID,
+-						COMPOUND_FID, current->tgid,
+-						FILE_DISPOSITION_INFORMATION,
+-						SMB2_O_INFO_FILE, 0, data, size);
+-			if (rc)
++			if (cfile) {
++				rc = SMB2_set_info_init(tcon, server,
++							&rqst[num_rqst],
++							cfile->fid.persistent_fid,
++							cfile->fid.volatile_fid,
++							current->tgid,
++							FILE_DISPOSITION_INFORMATION,
++							SMB2_O_INFO_FILE, 0,
++							data, size);
++			} else {
++				rc = SMB2_set_info_init(tcon, server,
++							&rqst[num_rqst],
++							COMPOUND_FID,
++							COMPOUND_FID,
++							current->tgid,
++							FILE_DISPOSITION_INFORMATION,
++							SMB2_O_INFO_FILE, 0,
++							data, size);
++			}
++			if (!rc && (!cfile || num_rqst > 1)) {
++				smb2_set_next_command(tcon, &rqst[num_rqst]);
++				smb2_set_related(&rqst[num_rqst]);
++			} else if (rc) {
+ 				goto finished;
+-			smb2_set_next_command(tcon, &rqst[num_rqst]);
+-			smb2_set_related(&rqst[num_rqst++]);
+-			trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, full_path);
++			}
++			num_rqst++;
++			trace_smb3_unlink_enter(xid, tcon->tid, ses->Suid, full_path);
+ 			break;
+ 		case SMB2_OP_SET_EOF:
+ 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
+@@ -442,7 +456,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ 							   ses->Suid, full_path);
+ 			break;
+ 		case SMB2_OP_RENAME:
+-			rqst[num_rqst].rq_iov = &vars->si_iov[0];
++			rqst[num_rqst].rq_iov = vars->rename_iov;
+ 			rqst[num_rqst].rq_nvec = 2;
+ 
+ 			len = in_iov[i].iov_len;
+@@ -732,19 +746,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ 				trace_smb3_posix_query_info_compound_done(xid, tcon->tid,
+ 									  ses->Suid);
+ 			break;
+-		case SMB2_OP_DELETE:
+-			if (rc)
+-				trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc);
+-			else {
+-				/*
+-				 * If dentry (hence, inode) is NULL, lease break is going to
+-				 * take care of degrading leases on handles for deleted files.
+-				 */
+-				if (inode)
+-					cifs_mark_open_handles_for_deleted_file(inode, full_path);
+-				trace_smb3_delete_done(xid, tcon->tid, ses->Suid);
+-			}
+-			break;
+ 		case SMB2_OP_MKDIR:
+ 			if (rc)
+ 				trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc);
+@@ -765,11 +766,11 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ 				trace_smb3_rename_done(xid, tcon->tid, ses->Suid);
+ 			SMB2_set_info_free(&rqst[num_rqst++]);
+ 			break;
+-		case SMB2_OP_RMDIR:
+-			if (rc)
+-				trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc);
++		case SMB2_OP_UNLINK:
++			if (!rc)
++				trace_smb3_unlink_done(xid, tcon->tid, ses->Suid);
+ 			else
+-				trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid);
++				trace_smb3_unlink_err(xid, tcon->tid, ses->Suid, rc);
+ 			SMB2_set_info_free(&rqst[num_rqst++]);
+ 			break;
+ 		case SMB2_OP_SET_EOF:
+@@ -1165,7 +1166,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ 			     FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
+ 	return smb2_compound_op(xid, tcon, cifs_sb,
+ 				name, &oparms, NULL,
+-				&(int){SMB2_OP_RMDIR}, 1,
++				&(int){SMB2_OP_UNLINK}, 1,
+ 				NULL, NULL, NULL, NULL);
+ }
+ 
+@@ -1174,20 +1175,29 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ 	    struct cifs_sb_info *cifs_sb, struct dentry *dentry)
+ {
+ 	struct cifs_open_parms oparms;
++	struct inode *inode = NULL;
++	int rc;
+ 
+-	oparms = CIFS_OPARMS(cifs_sb, tcon, name,
+-			     DELETE, FILE_OPEN,
+-			     CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
+-			     ACL_NO_MODE);
+-	int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
+-				  NULL, &(int){SMB2_OP_DELETE}, 1,
+-				  NULL, NULL, NULL, dentry);
++	if (dentry)
++		inode = d_inode(dentry);
++
++	oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
++			     FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
++	rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
++			      NULL, &(int){SMB2_OP_UNLINK},
++			      1, NULL, NULL, NULL, dentry);
+ 	if (rc == -EINVAL) {
+ 		cifs_dbg(FYI, "invalid lease key, resending request without lease");
+ 		rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
+-				      NULL, &(int){SMB2_OP_DELETE}, 1,
+-				      NULL, NULL, NULL, NULL);
++				      NULL, &(int){SMB2_OP_UNLINK},
++				      1, NULL, NULL, NULL, NULL);
+ 	}
++	/*
++	 * If dentry (hence, inode) is NULL, lease break is going to
++	 * take care of degrading leases on handles for deleted files.
++	 */
++	if (!rc && inode)
++		cifs_mark_open_handles_for_deleted_file(inode, name);
+ 	return rc;
+ }
+ 
+@@ -1441,3 +1451,113 @@ int smb2_query_reparse_point(const unsigned int xid,
+ 	cifs_free_open_info(&data);
+ 	return rc;
+ }
++
++static inline __le16 *utf16_smb2_path(struct cifs_sb_info *cifs_sb,
++				      const char *name, size_t namelen)
++{
++	int len;
++
++	if (*name == '\\' ||
++	    (cifs_sb_master_tlink(cifs_sb) &&
++	     cifs_sb_master_tcon(cifs_sb)->posix_extensions && *name == '/'))
++		name++;
++	return cifs_strndup_to_utf16(name, namelen, &len,
++				     cifs_sb->local_nls,
++				     cifs_remap(cifs_sb));
++}
++
++int smb2_rename_pending_delete(const char *full_path,
++			       struct dentry *dentry,
++			       const unsigned int xid)
++{
++	struct cifs_sb_info *cifs_sb = CIFS_SB(d_inode(dentry)->i_sb);
++	struct cifsInodeInfo *cinode = CIFS_I(d_inode(dentry));
++	__le16 *utf16_path __free(kfree) = NULL;
++	__u32 co = file_create_options(dentry);
++	int cmds[] = {
++		SMB2_OP_SET_INFO,
++		SMB2_OP_RENAME,
++		SMB2_OP_UNLINK,
++	};
++	const int num_cmds = ARRAY_SIZE(cmds);
++	char *to_name __free(kfree) = NULL;
++	__u32 attrs = cinode->cifsAttrs;
++	struct cifs_open_parms oparms;
++	static atomic_t sillycounter;
++	struct cifsFileInfo *cfile;
++	struct tcon_link *tlink;
++	struct cifs_tcon *tcon;
++	struct kvec iov[2];
++	const char *ppath;
++	void *page;
++	size_t len;
++	int rc;
++
++	tlink = cifs_sb_tlink(cifs_sb);
++	if (IS_ERR(tlink))
++		return PTR_ERR(tlink);
++	tcon = tlink_tcon(tlink);
++
++	page = alloc_dentry_path();
++
++	ppath = build_path_from_dentry(dentry->d_parent, page);
++	if (IS_ERR(ppath)) {
++		rc = PTR_ERR(ppath);
++		goto out;
++	}
++
++	len = strlen(ppath) + strlen("/.__smb1234") + 1;
++	to_name = kmalloc(len, GFP_KERNEL);
++	if (!to_name) {
++		rc = -ENOMEM;
++		goto out;
++	}
++
++	scnprintf(to_name, len, "%s%c.__smb%04X", ppath, CIFS_DIR_SEP(cifs_sb),
++		  atomic_inc_return(&sillycounter) & 0xffff);
++
++	utf16_path = utf16_smb2_path(cifs_sb, to_name, len);
++	if (!utf16_path) {
++		rc = -ENOMEM;
++		goto out;
++	}
++
++	drop_cached_dir_by_name(xid, tcon, full_path, cifs_sb);
++	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
++			     DELETE | FILE_WRITE_ATTRIBUTES,
++			     FILE_OPEN, co, ACL_NO_MODE);
++
++	attrs &= ~ATTR_READONLY;
++	if (!attrs)
++		attrs = ATTR_NORMAL;
++	if (d_inode(dentry)->i_nlink <= 1)
++		attrs |= ATTR_HIDDEN;
++	iov[0].iov_base = &(FILE_BASIC_INFO) {
++		.Attributes = cpu_to_le32(attrs),
++	};
++	iov[0].iov_len = sizeof(FILE_BASIC_INFO);
++	iov[1].iov_base = utf16_path;
++	iov[1].iov_len = sizeof(*utf16_path) * UniStrlen((wchar_t *)utf16_path);
++
++	cifs_get_writable_path(tcon, full_path, FIND_WR_WITH_DELETE, &cfile);
++	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
++			      cmds, num_cmds, cfile, NULL, NULL, dentry);
++	if (rc == -EINVAL) {
++		cifs_dbg(FYI, "invalid lease key, resending request without lease\n");
++		cifs_get_writable_path(tcon, full_path,
++				       FIND_WR_WITH_DELETE, &cfile);
++		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, iov,
++				      cmds, num_cmds, cfile, NULL, NULL, NULL);
++	}
++	if (!rc) {
++		set_bit(CIFS_INO_DELETE_PENDING, &cinode->flags);
++	} else {
++		cifs_tcon_dbg(FYI, "%s: failed to rename '%s' to '%s': %d\n",
++			      __func__, full_path, to_name, rc);
++		rc = -EIO;
++	}
++out:
++	cifs_put_tlink(tlink);
++	free_dentry_path(page);
++	return rc;
++}
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index d3e09b10dea476..cd051bb1a9d608 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -2640,13 +2640,35 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
+ 	}
+ 
+ 	/* SMB headers in a compound are 8 byte aligned. */
+-	if (!IS_ALIGNED(len, 8)) {
+-		num_padding = 8 - (len & 7);
++	if (IS_ALIGNED(len, 8))
++		goto out;
++
++	num_padding = 8 - (len & 7);
++	if (smb3_encryption_required(tcon)) {
++		int i;
++
++		/*
++		 * Flatten request into a single buffer with required padding as
++		 * the encryption layer can't handle the padding iovs.
++		 */
++		for (i = 1; i < rqst->rq_nvec; i++) {
++			memcpy(rqst->rq_iov[0].iov_base +
++			       rqst->rq_iov[0].iov_len,
++			       rqst->rq_iov[i].iov_base,
++			       rqst->rq_iov[i].iov_len);
++			rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
++		}
++		memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
++		       0, num_padding);
++		rqst->rq_iov[0].iov_len += num_padding;
++		rqst->rq_nvec = 1;
++	} else {
+ 		rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
+ 		rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
+ 		rqst->rq_nvec++;
+-		len += num_padding;
+ 	}
++	len += num_padding;
++out:
+ 	shdr->NextCommand = cpu_to_le32(len);
+ }
+ 
+@@ -5377,6 +5399,7 @@ struct smb_version_operations smb20_operations = {
+ 	.llseek = smb3_llseek,
+ 	.is_status_io_timeout = smb2_is_status_io_timeout,
+ 	.is_network_name_deleted = smb2_is_network_name_deleted,
++	.rename_pending_delete = smb2_rename_pending_delete,
+ };
+ #endif /* CIFS_ALLOW_INSECURE_LEGACY */
+ 
+@@ -5482,6 +5505,7 @@ struct smb_version_operations smb21_operations = {
+ 	.llseek = smb3_llseek,
+ 	.is_status_io_timeout = smb2_is_status_io_timeout,
+ 	.is_network_name_deleted = smb2_is_network_name_deleted,
++	.rename_pending_delete = smb2_rename_pending_delete,
+ };
+ 
+ struct smb_version_operations smb30_operations = {
+@@ -5598,6 +5622,7 @@ struct smb_version_operations smb30_operations = {
+ 	.llseek = smb3_llseek,
+ 	.is_status_io_timeout = smb2_is_status_io_timeout,
+ 	.is_network_name_deleted = smb2_is_network_name_deleted,
++	.rename_pending_delete = smb2_rename_pending_delete,
+ };
+ 
+ struct smb_version_operations smb311_operations = {
+@@ -5714,6 +5739,7 @@ struct smb_version_operations smb311_operations = {
+ 	.llseek = smb3_llseek,
+ 	.is_status_io_timeout = smb2_is_status_io_timeout,
+ 	.is_network_name_deleted = smb2_is_network_name_deleted,
++	.rename_pending_delete = smb2_rename_pending_delete,
+ };
+ 
+ #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
+diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
+index 035aa16240535c..8d6b42ff38fe68 100644
+--- a/fs/smb/client/smb2proto.h
++++ b/fs/smb/client/smb2proto.h
+@@ -320,5 +320,8 @@ int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
+ int smb2_make_nfs_node(unsigned int xid, struct inode *inode,
+ 		       struct dentry *dentry, struct cifs_tcon *tcon,
+ 		       const char *full_path, umode_t mode, dev_t dev);
++int smb2_rename_pending_delete(const char *full_path,
++			       struct dentry *dentry,
++			       const unsigned int xid);
+ 
+ #endif			/* _SMB2PROTO_H */
+diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
+index 93e5b2bb9f28a2..a8c6f11699a3b6 100644
+--- a/fs/smb/client/trace.h
++++ b/fs/smb/client/trace.h
+@@ -669,13 +669,12 @@ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_info_compound_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(posix_query_info_compound_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(hardlink_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rename_enter);
+-DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter);
++DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(unlink_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_eof_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_reparse_compound_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(get_reparse_compound_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(query_wsl_ea_compound_enter);
+-DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter);
+ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mknod_enter);
+@@ -710,13 +709,12 @@ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_info_compound_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(posix_query_info_compound_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(hardlink_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rename_done);
+-DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done);
++DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(unlink_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_eof_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_info_compound_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_reparse_compound_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(get_reparse_compound_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(query_wsl_ea_compound_done);
+-DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(delete_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mkdir_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(tdis_done);
+ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mknod_done);
+@@ -756,14 +754,13 @@ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_info_compound_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(posix_query_info_compound_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(hardlink_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rename_err);
+-DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err);
++DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(unlink_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_eof_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_info_compound_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_reparse_compound_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(get_reparse_compound_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(query_wsl_ea_compound_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mkdir_err);
+-DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(delete_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(tdis_err);
+ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mknod_err);
+ 
+diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h
+index e4ca35143ff965..3e35a68b2b4122 100644
+--- a/include/drm/display/drm_dp_helper.h
++++ b/include/drm/display/drm_dp_helper.h
+@@ -523,10 +523,16 @@ struct drm_dp_aux {
+ 	 * @no_zero_sized: If the hw can't use zero sized transfers (NVIDIA)
+ 	 */
+ 	bool no_zero_sized;
++
++	/**
++	 * @dpcd_probe_disabled: If probing before a DPCD access is disabled.
++	 */
++	bool dpcd_probe_disabled;
+ };
+ 
+ int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset);
+ void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered);
++void drm_dp_dpcd_set_probe(struct drm_dp_aux *aux, bool enable);
+ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
+ 			 void *buffer, size_t size);
+ ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
+diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
+index f13d597370a30d..da49d520aa3bae 100644
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -843,7 +843,9 @@ struct drm_display_info {
+ 	int vics_len;
+ 
+ 	/**
+-	 * @quirks: EDID based quirks. Internal to EDID parsing.
++	 * @quirks: EDID based quirks. DRM core and drivers can query the
++	 * @drm_edid_quirk quirks using drm_edid_has_quirk(), the rest of
++	 * the quirks also tracked here are internal to EDID parsing.
+ 	 */
+ 	u32 quirks;
+ 
+diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
+index b38409670868d8..3d1aecfec9b2a4 100644
+--- a/include/drm/drm_edid.h
++++ b/include/drm/drm_edid.h
+@@ -109,6 +109,13 @@ struct detailed_data_string {
+ #define DRM_EDID_CVT_FLAGS_STANDARD_BLANKING (1 << 3)
+ #define DRM_EDID_CVT_FLAGS_REDUCED_BLANKING  (1 << 4)
+ 
++enum drm_edid_quirk {
++	/* Do a dummy read before DPCD accesses, to prevent corruption. */
++	DRM_EDID_QUIRK_DP_DPCD_PROBE,
++
++	DRM_EDID_QUIRK_NUM,
++};
++
+ struct detailed_data_monitor_range {
+ 	u8 min_vfreq;
+ 	u8 max_vfreq;
+@@ -476,5 +483,6 @@ void drm_edid_print_product_id(struct drm_printer *p,
+ u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid);
+ bool drm_edid_match(const struct drm_edid *drm_edid,
+ 		    const struct drm_edid_ident *ident);
++bool drm_edid_has_quirk(struct drm_connector *connector, enum drm_edid_quirk quirk);
+ 
+ #endif /* __DRM_EDID_H__ */
+diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h
+index 4fc8e26914adfd..f9f36d6af9a710 100644
+--- a/include/linux/compiler-clang.h
++++ b/include/linux/compiler-clang.h
+@@ -18,23 +18,42 @@
+ #define KASAN_ABI_VERSION 5
+ 
+ /*
++ * Clang 22 added preprocessor macros to match GCC, in hopes of eventually
++ * dropping __has_feature support for sanitizers:
++ * https://github.com/llvm/llvm-project/commit/568c23bbd3303518c5056d7f03444dae4fdc8a9c
++ * Create these macros for older versions of clang so that it is easy to clean
++ * up once the minimum supported version of LLVM for building the kernel always
++ * creates these macros.
++ *
+  * Note: Checking __has_feature(*_sanitizer) is only true if the feature is
+  * enabled. Therefore it is not required to additionally check defined(CONFIG_*)
+  * to avoid adding redundant attributes in other configurations.
+  */
++#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
++#define __SANITIZE_ADDRESS__
++#endif
++#if __has_feature(hwaddress_sanitizer) && !defined(__SANITIZE_HWADDRESS__)
++#define __SANITIZE_HWADDRESS__
++#endif
++#if __has_feature(thread_sanitizer) && !defined(__SANITIZE_THREAD__)
++#define __SANITIZE_THREAD__
++#endif
+ 
+-#if __has_feature(address_sanitizer) || __has_feature(hwaddress_sanitizer)
+-/* Emulate GCC's __SANITIZE_ADDRESS__ flag */
++/*
++ * Treat __SANITIZE_HWADDRESS__ the same as __SANITIZE_ADDRESS__ in the kernel.
++ */
++#ifdef __SANITIZE_HWADDRESS__
+ #define __SANITIZE_ADDRESS__
++#endif
++
++#ifdef __SANITIZE_ADDRESS__
+ #define __no_sanitize_address \
+ 		__attribute__((no_sanitize("address", "hwaddress")))
+ #else
+ #define __no_sanitize_address
+ #endif
+ 
+-#if __has_feature(thread_sanitizer)
+-/* emulate gcc's __SANITIZE_THREAD__ flag */
+-#define __SANITIZE_THREAD__
++#ifdef __SANITIZE_THREAD__
+ #define __no_sanitize_thread \
+ 		__attribute__((no_sanitize("thread")))
+ #else
+diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
+index 7fa1eb3cc82399..61d50571ad88ac 100644
+--- a/include/linux/energy_model.h
++++ b/include/linux/energy_model.h
+@@ -171,6 +171,9 @@ int em_dev_update_perf_domain(struct device *dev,
+ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+ 				const struct em_data_callback *cb,
+ 				const cpumask_t *cpus, bool microwatts);
++int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
++				 const struct em_data_callback *cb,
++				 const cpumask_t *cpus, bool microwatts);
+ void em_dev_unregister_perf_domain(struct device *dev);
+ struct em_perf_table *em_table_alloc(struct em_perf_domain *pd);
+ void em_table_free(struct em_perf_table *table);
+@@ -350,6 +353,13 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+ {
+ 	return -EINVAL;
+ }
++static inline
++int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
++				 const struct em_data_callback *cb,
++				 const cpumask_t *cpus, bool microwatts)
++{
++	return -EINVAL;
++}
+ static inline void em_dev_unregister_perf_domain(struct device *dev)
+ {
+ }
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 040c0036320fdf..d6716ff498a7aa 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -149,7 +149,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
+ /* Expect random access pattern */
+ #define FMODE_RANDOM		((__force fmode_t)(1 << 12))
+ 
+-/* FMODE_* bit 13 */
++/* Supports IOCB_HAS_METADATA */
++#define FMODE_HAS_METADATA	((__force fmode_t)(1 << 13))
+ 
+ /* File is opened with O_PATH; almost nothing can be done with it */
+ #define FMODE_PATH		((__force fmode_t)(1 << 14))
+diff --git a/include/linux/kasan.h b/include/linux/kasan.h
+index 890011071f2b14..fe5ce9215821db 100644
+--- a/include/linux/kasan.h
++++ b/include/linux/kasan.h
+@@ -562,7 +562,7 @@ static inline void kasan_init_hw_tags(void) { }
+ #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
+ 
+ void kasan_populate_early_vm_area_shadow(void *start, unsigned long size);
+-int kasan_populate_vmalloc(unsigned long addr, unsigned long size);
++int kasan_populate_vmalloc(unsigned long addr, unsigned long size, gfp_t gfp_mask);
+ void kasan_release_vmalloc(unsigned long start, unsigned long end,
+ 			   unsigned long free_region_start,
+ 			   unsigned long free_region_end,
+@@ -574,7 +574,7 @@ static inline void kasan_populate_early_vm_area_shadow(void *start,
+ 						       unsigned long size)
+ { }
+ static inline int kasan_populate_vmalloc(unsigned long start,
+-					unsigned long size)
++					unsigned long size, gfp_t gfp_mask)
+ {
+ 	return 0;
+ }
+@@ -610,7 +610,7 @@ static __always_inline void kasan_poison_vmalloc(const void *start,
+ static inline void kasan_populate_early_vm_area_shadow(void *start,
+ 						       unsigned long size) { }
+ static inline int kasan_populate_vmalloc(unsigned long start,
+-					unsigned long size)
++					unsigned long size, gfp_t gfp_mask)
+ {
+ 	return 0;
+ }
+diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
+index 15eaa09da998ce..d668b6266c34a2 100644
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -484,6 +484,7 @@ struct spinand_user_otp {
+  * @op_variants.update_cache: variants of the update-cache operation
+  * @select_target: function used to select a target/die. Required only for
+  *		   multi-die chips
++ * @configure_chip: Align the chip configuration with the core settings
+  * @set_cont_read: enable/disable continuous cached reads
+  * @fact_otp: SPI NAND factory OTP info.
+  * @user_otp: SPI NAND user OTP info.
+@@ -507,6 +508,7 @@ struct spinand_info {
+ 	} op_variants;
+ 	int (*select_target)(struct spinand_device *spinand,
+ 			     unsigned int target);
++	int (*configure_chip)(struct spinand_device *spinand);
+ 	int (*set_cont_read)(struct spinand_device *spinand,
+ 			     bool enable);
+ 	struct spinand_fact_otp fact_otp;
+@@ -539,6 +541,9 @@ struct spinand_info {
+ #define SPINAND_SELECT_TARGET(__func)					\
+ 	.select_target = __func
+ 
++#define SPINAND_CONFIGURE_CHIP(__configure_chip)			\
++	.configure_chip = __configure_chip
++
+ #define SPINAND_CONT_READ(__set_cont_read)				\
+ 	.set_cont_read = __set_cont_read
+ 
+@@ -607,6 +612,7 @@ struct spinand_dirmap {
+  *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
+  *		the stack
+  * @manufacturer: SPI NAND manufacturer information
++ * @configure_chip: Align the chip configuration with the core settings
+  * @cont_read_possible: Field filled by the core once the whole system
+  *		configuration is known to tell whether continuous reads are
+  *		suitable to use or not in general with this chip/configuration.
+@@ -647,6 +653,7 @@ struct spinand_device {
+ 	const struct spinand_manufacturer *manufacturer;
+ 	void *priv;
+ 
++	int (*configure_chip)(struct spinand_device *spinand);
+ 	bool cont_read_possible;
+ 	int (*set_cont_read)(struct spinand_device *spinand,
+ 			     bool enable);
+@@ -723,6 +730,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
+ 			   enum spinand_readid_method rdid_method);
+ 
+ int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
++int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val);
+ int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val);
+ int spinand_select_target(struct spinand_device *spinand, unsigned int target);
+ 
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index 5e49619ae49c69..16daeac2ac555e 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -459,19 +459,17 @@ struct nft_set_ext;
+  *	control plane functions.
+  */
+ struct nft_set_ops {
+-	bool				(*lookup)(const struct net *net,
++	const struct nft_set_ext *	(*lookup)(const struct net *net,
+ 						  const struct nft_set *set,
+-						  const u32 *key,
+-						  const struct nft_set_ext **ext);
+-	bool				(*update)(struct nft_set *set,
++						  const u32 *key);
++	const struct nft_set_ext *	(*update)(struct nft_set *set,
+ 						  const u32 *key,
+ 						  struct nft_elem_priv *
+ 							(*new)(struct nft_set *,
+ 							       const struct nft_expr *,
+ 							       struct nft_regs *),
+ 						  const struct nft_expr *expr,
+-						  struct nft_regs *regs,
+-						  const struct nft_set_ext **ext);
++						  struct nft_regs *regs);
+ 	bool				(*delete)(const struct nft_set *set,
+ 						  const u32 *key);
+ 
+@@ -1918,7 +1916,6 @@ struct nftables_pernet {
+ 	struct mutex		commit_mutex;
+ 	u64			table_handle;
+ 	u64			tstamp;
+-	unsigned int		base_seq;
+ 	unsigned int		gc_seq;
+ 	u8			validate_state;
+ 	struct work_struct	destroy_work;
+diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h
+index 03b6165756fc5d..04699eac5b5243 100644
+--- a/include/net/netfilter/nf_tables_core.h
++++ b/include/net/netfilter/nf_tables_core.h
+@@ -94,34 +94,35 @@ extern const struct nft_set_type nft_set_pipapo_type;
+ extern const struct nft_set_type nft_set_pipapo_avx2_type;
+ 
+ #ifdef CONFIG_MITIGATION_RETPOLINE
+-bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
+-		      const u32 *key, const struct nft_set_ext **ext);
+-bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext);
+-bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext);
+-bool nft_hash_lookup_fast(const struct net *net,
+-			  const struct nft_set *set,
+-			  const u32 *key, const struct nft_set_ext **ext);
+-bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
+-		     const u32 *key, const struct nft_set_ext **ext);
+-bool nft_set_do_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext);
+-#else
+-static inline bool
+-nft_set_do_lookup(const struct net *net, const struct nft_set *set,
+-		  const u32 *key, const struct nft_set_ext **ext)
+-{
+-	return set->ops->lookup(net, set, key, ext);
+-}
++const struct nft_set_ext *
++nft_rhash_lookup(const struct net *net, const struct nft_set *set,
++		 const u32 *key);
++const struct nft_set_ext *
++nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key);
++const struct nft_set_ext *
++nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key);
++const struct nft_set_ext *
++nft_hash_lookup_fast(const struct net *net, const struct nft_set *set,
++		     const u32 *key);
++const struct nft_set_ext *
++nft_hash_lookup(const struct net *net, const struct nft_set *set,
++		const u32 *key);
+ #endif
+ 
++const struct nft_set_ext *
++nft_set_do_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key);
++
+ /* called from nft_pipapo_avx2.c */
+-bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext);
++const struct nft_set_ext *
++nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key);
+ /* called from nft_set_pipapo.c */
+-bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
+-			    const u32 *key, const struct nft_set_ext **ext);
++const struct nft_set_ext *
++nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
++			const u32 *key);
+ 
+ void nft_counter_init_seqcount(void);
+ 
+diff --git a/include/net/netns/nftables.h b/include/net/netns/nftables.h
+index cc8060c017d5fb..99dd166c5d07c3 100644
+--- a/include/net/netns/nftables.h
++++ b/include/net/netns/nftables.h
+@@ -3,6 +3,7 @@
+ #define _NETNS_NFTABLES_H_
+ 
+ struct netns_nftables {
++	unsigned int		base_seq;
+ 	u8			gencursor;
+ };
+ 
+diff --git a/include/uapi/linux/raid/md_p.h b/include/uapi/linux/raid/md_p.h
+index b1394628727758..ac74133a476887 100644
+--- a/include/uapi/linux/raid/md_p.h
++++ b/include/uapi/linux/raid/md_p.h
+@@ -173,7 +173,7 @@ typedef struct mdp_superblock_s {
+ #else
+ #error unspecified endianness
+ #endif
+-	__u32 resync_offset;	/* 11 resync checkpoint sector count	      */
++	__u32 recovery_cp;	/* 11 resync checkpoint sector count	      */
+ 	/* There are only valid for minor_version > 90 */
+ 	__u64 reshape_position;	/* 12,13 next address in array-space for reshape */
+ 	__u32 new_level;	/* 14 new level we are reshaping to	      */
+diff --git a/io_uring/rw.c b/io_uring/rw.c
+index 52a5b950b2e5e9..af5a54b5db1233 100644
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -886,6 +886,9 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode, int rw_type)
+ 	if (req->flags & REQ_F_HAS_METADATA) {
+ 		struct io_async_rw *io = req->async_data;
+ 
++		if (!(file->f_mode & FMODE_HAS_METADATA))
++			return -EINVAL;
++
+ 		/*
+ 		 * We have a union of meta fields with wpq used for buffered-io
+ 		 * in io_async_rw, so fail it here.
+diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
+index 3a335c50e6e3cb..12ec926ed7114e 100644
+--- a/kernel/bpf/Makefile
++++ b/kernel/bpf/Makefile
+@@ -62,3 +62,4 @@ CFLAGS_REMOVE_bpf_lru_list.o = $(CC_FLAGS_FTRACE)
+ CFLAGS_REMOVE_queue_stack_maps.o = $(CC_FLAGS_FTRACE)
+ CFLAGS_REMOVE_lpm_trie.o = $(CC_FLAGS_FTRACE)
+ CFLAGS_REMOVE_ringbuf.o = $(CC_FLAGS_FTRACE)
++CFLAGS_REMOVE_rqspinlock.o = $(CC_FLAGS_FTRACE)
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index d966e971893ab3..829f0792d8d831 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -2354,8 +2354,7 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx,
+ 					 const struct bpf_insn *insn)
+ {
+ 	/* If this handler ever gets executed, then BPF_JIT_ALWAYS_ON
+-	 * is not working properly, or interpreter is being used when
+-	 * prog->jit_requested is not 0, so warn about it!
++	 * is not working properly, so warn about it!
+ 	 */
+ 	WARN_ON_ONCE(1);
+ 	return 0;
+@@ -2456,8 +2455,9 @@ static int bpf_check_tail_call(const struct bpf_prog *fp)
+ 	return ret;
+ }
+ 
+-static void bpf_prog_select_func(struct bpf_prog *fp)
++static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
+ {
++	bool select_interpreter = false;
+ #ifndef CONFIG_BPF_JIT_ALWAYS_ON
+ 	u32 stack_depth = max_t(u32, fp->aux->stack_depth, 1);
+ 	u32 idx = (round_up(stack_depth, 32) / 32) - 1;
+@@ -2466,15 +2466,16 @@ static void bpf_prog_select_func(struct bpf_prog *fp)
+ 	 * But for non-JITed programs, we don't need bpf_func, so no bounds
+ 	 * check needed.
+ 	 */
+-	if (!fp->jit_requested &&
+-	    !WARN_ON_ONCE(idx >= ARRAY_SIZE(interpreters))) {
++	if (idx < ARRAY_SIZE(interpreters)) {
+ 		fp->bpf_func = interpreters[idx];
++		select_interpreter = true;
+ 	} else {
+ 		fp->bpf_func = __bpf_prog_ret0_warn;
+ 	}
+ #else
+ 	fp->bpf_func = __bpf_prog_ret0_warn;
+ #endif
++	return select_interpreter;
+ }
+ 
+ /**
+@@ -2493,7 +2494,7 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
+ 	/* In case of BPF to BPF calls, verifier did all the prep
+ 	 * work with regards to JITing, etc.
+ 	 */
+-	bool jit_needed = fp->jit_requested;
++	bool jit_needed = false;
+ 
+ 	if (fp->bpf_func)
+ 		goto finalize;
+@@ -2502,7 +2503,8 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
+ 	    bpf_prog_has_kfunc_call(fp))
+ 		jit_needed = true;
+ 
+-	bpf_prog_select_func(fp);
++	if (!bpf_prog_select_interpreter(fp))
++		jit_needed = true;
+ 
+ 	/* eBPF JITs can rewrite the program in case constant
+ 	 * blinding is active. However, in case of error during
+diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
+index 67e8a2fc1a99de..cfcf7ed57ca0d2 100644
+--- a/kernel/bpf/cpumap.c
++++ b/kernel/bpf/cpumap.c
+@@ -186,7 +186,6 @@ static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu,
+ 	struct xdp_buff xdp;
+ 	int i, nframes = 0;
+ 
+-	xdp_set_return_frame_no_direct();
+ 	xdp.rxq = &rxq;
+ 
+ 	for (i = 0; i < n; i++) {
+@@ -231,7 +230,6 @@ static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu,
+ 		}
+ 	}
+ 
+-	xdp_clear_return_frame_no_direct();
+ 	stats->pass += nframes;
+ 
+ 	return nframes;
+@@ -255,6 +253,7 @@ static void cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames,
+ 
+ 	rcu_read_lock();
+ 	bpf_net_ctx = bpf_net_ctx_set(&__bpf_net_ctx);
++	xdp_set_return_frame_no_direct();
+ 
+ 	ret->xdp_n = cpu_map_bpf_prog_run_xdp(rcpu, frames, ret->xdp_n, stats);
+ 	if (unlikely(ret->skb_n))
+@@ -264,6 +263,7 @@ static void cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames,
+ 	if (stats->redirect)
+ 		xdp_do_flush();
+ 
++	xdp_clear_return_frame_no_direct();
+ 	bpf_net_ctx_clear(bpf_net_ctx);
+ 	rcu_read_unlock();
+ 
+diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c
+index 94854cd9c4cc32..83c4d9943084b9 100644
+--- a/kernel/bpf/crypto.c
++++ b/kernel/bpf/crypto.c
+@@ -278,7 +278,7 @@ static int bpf_crypto_crypt(const struct bpf_crypto_ctx *ctx,
+ 	siv_len = siv ? __bpf_dynptr_size(siv) : 0;
+ 	src_len = __bpf_dynptr_size(src);
+ 	dst_len = __bpf_dynptr_size(dst);
+-	if (!src_len || !dst_len)
++	if (!src_len || !dst_len || src_len > dst_len)
+ 		return -EINVAL;
+ 
+ 	if (siv_len != ctx->siv_len)
+diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
+index fdf8737542ac45..3abbdebb2d9efc 100644
+--- a/kernel/bpf/helpers.c
++++ b/kernel/bpf/helpers.c
+@@ -1277,8 +1277,11 @@ static int __bpf_async_init(struct bpf_async_kern *async, struct bpf_map *map, u
+ 		goto out;
+ 	}
+ 
+-	/* allocate hrtimer via map_kmalloc to use memcg accounting */
+-	cb = bpf_map_kmalloc_node(map, size, GFP_ATOMIC, map->numa_node);
++	/* Allocate via bpf_map_kmalloc_node() for memcg accounting. Until
++	 * kmalloc_nolock() is available, avoid locking issues by using
++	 * __GFP_HIGH (GFP_ATOMIC & ~__GFP_RECLAIM).
++	 */
++	cb = bpf_map_kmalloc_node(map, size, __GFP_HIGH, map->numa_node);
+ 	if (!cb) {
+ 		ret = -ENOMEM;
+ 		goto out;
+diff --git a/kernel/bpf/rqspinlock.c b/kernel/bpf/rqspinlock.c
+index 338305c8852cf6..804e619f1e0066 100644
+--- a/kernel/bpf/rqspinlock.c
++++ b/kernel/bpf/rqspinlock.c
+@@ -471,7 +471,7 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
+ 	 * any MCS node. This is not the most elegant solution, but is
+ 	 * simple enough.
+ 	 */
+-	if (unlikely(idx >= _Q_MAX_NODES)) {
++	if (unlikely(idx >= _Q_MAX_NODES || in_nmi())) {
+ 		lockevent_inc(lock_no_node);
+ 		RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT);
+ 		while (!queued_spin_trylock(lock)) {
+diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c
+index e43c6de2bce4e7..b82399437db031 100644
+--- a/kernel/dma/debug.c
++++ b/kernel/dma/debug.c
+@@ -39,6 +39,7 @@ enum {
+ 	dma_debug_sg,
+ 	dma_debug_coherent,
+ 	dma_debug_resource,
++	dma_debug_noncoherent,
+ };
+ 
+ enum map_err_types {
+@@ -141,6 +142,7 @@ static const char *type2name[] = {
+ 	[dma_debug_sg] = "scatter-gather",
+ 	[dma_debug_coherent] = "coherent",
+ 	[dma_debug_resource] = "resource",
++	[dma_debug_noncoherent] = "noncoherent",
+ };
+ 
+ static const char *dir2name[] = {
+@@ -993,7 +995,8 @@ static void check_unmap(struct dma_debug_entry *ref)
+ 			   "[mapped as %s] [unmapped as %s]\n",
+ 			   ref->dev_addr, ref->size,
+ 			   type2name[entry->type], type2name[ref->type]);
+-	} else if (entry->type == dma_debug_coherent &&
++	} else if ((entry->type == dma_debug_coherent ||
++		    entry->type == dma_debug_noncoherent) &&
+ 		   ref->paddr != entry->paddr) {
+ 		err_printk(ref->dev, entry, "device driver frees "
+ 			   "DMA memory with different CPU address "
+@@ -1581,6 +1584,49 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ 	}
+ }
+ 
++void debug_dma_alloc_pages(struct device *dev, struct page *page,
++			   size_t size, int direction,
++			   dma_addr_t dma_addr,
++			   unsigned long attrs)
++{
++	struct dma_debug_entry *entry;
++
++	if (unlikely(dma_debug_disabled()))
++		return;
++
++	entry = dma_entry_alloc();
++	if (!entry)
++		return;
++
++	entry->type      = dma_debug_noncoherent;
++	entry->dev       = dev;
++	entry->paddr	 = page_to_phys(page);
++	entry->size      = size;
++	entry->dev_addr  = dma_addr;
++	entry->direction = direction;
++
++	add_dma_entry(entry, attrs);
++}
++
++void debug_dma_free_pages(struct device *dev, struct page *page,
++			  size_t size, int direction,
++			  dma_addr_t dma_addr)
++{
++	struct dma_debug_entry ref = {
++		.type           = dma_debug_noncoherent,
++		.dev            = dev,
++		.paddr		= page_to_phys(page),
++		.dev_addr       = dma_addr,
++		.size           = size,
++		.direction      = direction,
++	};
++
++	if (unlikely(dma_debug_disabled()))
++		return;
++
++	check_unmap(&ref);
++}
++
+ static int __init dma_debug_driver_setup(char *str)
+ {
+ 	int i;
+diff --git a/kernel/dma/debug.h b/kernel/dma/debug.h
+index f525197d3cae60..48757ca13f3140 100644
+--- a/kernel/dma/debug.h
++++ b/kernel/dma/debug.h
+@@ -54,6 +54,13 @@ extern void debug_dma_sync_sg_for_cpu(struct device *dev,
+ extern void debug_dma_sync_sg_for_device(struct device *dev,
+ 					 struct scatterlist *sg,
+ 					 int nelems, int direction);
++extern void debug_dma_alloc_pages(struct device *dev, struct page *page,
++				  size_t size, int direction,
++				  dma_addr_t dma_addr,
++				  unsigned long attrs);
++extern void debug_dma_free_pages(struct device *dev, struct page *page,
++				 size_t size, int direction,
++				 dma_addr_t dma_addr);
+ #else /* CONFIG_DMA_API_DEBUG */
+ static inline void debug_dma_map_page(struct device *dev, struct page *page,
+ 				      size_t offset, size_t size,
+@@ -126,5 +133,18 @@ static inline void debug_dma_sync_sg_for_device(struct device *dev,
+ 						int nelems, int direction)
+ {
+ }
++
++static inline void debug_dma_alloc_pages(struct device *dev, struct page *page,
++					 size_t size, int direction,
++					 dma_addr_t dma_addr,
++					 unsigned long attrs)
++{
++}
++
++static inline void debug_dma_free_pages(struct device *dev, struct page *page,
++					size_t size, int direction,
++					dma_addr_t dma_addr)
++{
++}
+ #endif /* CONFIG_DMA_API_DEBUG */
+ #endif /* _KERNEL_DMA_DEBUG_H */
+diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
+index 107e4a4d251df6..56de28a3b1799f 100644
+--- a/kernel/dma/mapping.c
++++ b/kernel/dma/mapping.c
+@@ -712,7 +712,7 @@ struct page *dma_alloc_pages(struct device *dev, size_t size,
+ 	if (page) {
+ 		trace_dma_alloc_pages(dev, page_to_virt(page), *dma_handle,
+ 				      size, dir, gfp, 0);
+-		debug_dma_map_page(dev, page, 0, size, dir, *dma_handle, 0);
++		debug_dma_alloc_pages(dev, page, size, dir, *dma_handle, 0);
+ 	} else {
+ 		trace_dma_alloc_pages(dev, NULL, 0, size, dir, gfp, 0);
+ 	}
+@@ -738,7 +738,7 @@ void dma_free_pages(struct device *dev, size_t size, struct page *page,
+ 		dma_addr_t dma_handle, enum dma_data_direction dir)
+ {
+ 	trace_dma_free_pages(dev, page_to_virt(page), dma_handle, size, dir, 0);
+-	debug_dma_unmap_page(dev, dma_handle, size, dir);
++	debug_dma_free_pages(dev, page, size, dir, dma_handle);
+ 	__dma_free_pages(dev, size, page, dma_handle, dir);
+ }
+ EXPORT_SYMBOL_GPL(dma_free_pages);
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 872122e074e5fe..820127536e62b7 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -10330,6 +10330,7 @@ static int __perf_event_overflow(struct perf_event *event,
+ 		ret = 1;
+ 		event->pending_kill = POLL_HUP;
+ 		perf_event_disable_inatomic(event);
++		event->pmu->stop(event, 0);
+ 	}
+ 
+ 	if (event->attr.sigtrap) {
+diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
+index ea7995a25780f3..8df55397414a12 100644
+--- a/kernel/power/energy_model.c
++++ b/kernel/power/energy_model.c
+@@ -552,6 +552,30 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
+ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+ 				const struct em_data_callback *cb,
+ 				const cpumask_t *cpus, bool microwatts)
++{
++	int ret = em_dev_register_pd_no_update(dev, nr_states, cb, cpus, microwatts);
++
++	if (_is_cpu_device(dev))
++		em_check_capacity_update();
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
++
++/**
++ * em_dev_register_pd_no_update() - Register a perf domain for a device
++ * @dev : Device to register the PD for
++ * @nr_states : Number of performance states in the new PD
++ * @cb : Callback functions for populating the energy model
++ * @cpus : CPUs to include in the new PD (mandatory if @dev is a CPU device)
++ * @microwatts : Whether or not the power values in the EM will be in uW
++ *
++ * Like em_dev_register_perf_domain(), but does not trigger a CPU capacity
++ * update after registering the PD, even if @dev is a CPU device.
++ */
++int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
++				 const struct em_data_callback *cb,
++				 const cpumask_t *cpus, bool microwatts)
+ {
+ 	struct em_perf_table *em_table;
+ 	unsigned long cap, prev_cap = 0;
+@@ -636,12 +660,9 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
+ unlock:
+ 	mutex_unlock(&em_pd_mutex);
+ 
+-	if (_is_cpu_device(dev))
+-		em_check_capacity_update();
+-
+ 	return ret;
+ }
+-EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
++EXPORT_SYMBOL_GPL(em_dev_register_pd_no_update);
+ 
+ /**
+  * em_dev_unregister_perf_domain() - Unregister Energy Model (EM) for a device
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index 9216e3b91d3b3b..c8022a477d3a1c 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -423,6 +423,7 @@ int hibernation_snapshot(int platform_mode)
+ 	}
+ 
+ 	console_suspend_all();
++	pm_restrict_gfp_mask();
+ 
+ 	error = dpm_suspend(PMSG_FREEZE);
+ 
+diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
+index 30899a8cc52c0a..e8c479329282f9 100644
+--- a/kernel/time/hrtimer.c
++++ b/kernel/time/hrtimer.c
+@@ -787,10 +787,10 @@ static void retrigger_next_event(void *arg)
+ 	 * of the next expiring timer is enough. The return from the SMP
+ 	 * function call will take care of the reprogramming in case the
+ 	 * CPU was in a NOHZ idle sleep.
++	 *
++	 * In periodic low resolution mode, the next softirq expiration
++	 * must also be updated.
+ 	 */
+-	if (!hrtimer_hres_active(base) && !tick_nohz_active)
+-		return;
+-
+ 	raw_spin_lock(&base->lock);
+ 	hrtimer_update_base(base);
+ 	if (hrtimer_hres_active(base))
+@@ -2295,11 +2295,6 @@ int hrtimers_cpu_dying(unsigned int dying_cpu)
+ 				     &new_base->clock_base[i]);
+ 	}
+ 
+-	/*
+-	 * The migration might have changed the first expiring softirq
+-	 * timer on this CPU. Update it.
+-	 */
+-	__hrtimer_get_next_event(new_base, HRTIMER_ACTIVE_SOFT);
+ 	/* Tell the other CPU to retrigger the next event */
+ 	smp_call_function_single(ncpu, retrigger_next_event, NULL, 0);
+ 
+diff --git a/kernel/trace/fgraph.c b/kernel/trace/fgraph.c
+index dac2d58f39490b..db40ec5cc9d731 100644
+--- a/kernel/trace/fgraph.c
++++ b/kernel/trace/fgraph.c
+@@ -1393,7 +1393,8 @@ int register_ftrace_graph(struct fgraph_ops *gops)
+ 		ftrace_graph_active--;
+ 		gops->saved_func = NULL;
+ 		fgraph_lru_release_index(i);
+-		unregister_pm_notifier(&ftrace_suspend_notifier);
++		if (!ftrace_graph_active)
++			unregister_pm_notifier(&ftrace_suspend_notifier);
+ 	}
+ 	return ret;
+ }
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index b91fa02cc54a6a..56f6cebdb22998 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -846,7 +846,10 @@ int trace_pid_write(struct trace_pid_list *filtered_pids,
+ 		/* copy the current bits to the new max */
+ 		ret = trace_pid_list_first(filtered_pids, &pid);
+ 		while (!ret) {
+-			trace_pid_list_set(pid_list, pid);
++			ret = trace_pid_list_set(pid_list, pid);
++			if (ret < 0)
++				goto out;
++
+ 			ret = trace_pid_list_next(filtered_pids, pid + 1, &pid);
+ 			nr_pids++;
+ 		}
+@@ -883,6 +886,7 @@ int trace_pid_write(struct trace_pid_list *filtered_pids,
+ 		trace_parser_clear(&parser);
+ 		ret = 0;
+ 	}
++ out:
+ 	trace_parser_put(&parser);
+ 
+ 	if (ret < 0) {
+@@ -7264,7 +7268,7 @@ static ssize_t write_marker_to_buffer(struct trace_array *tr, const char __user
+ 	entry = ring_buffer_event_data(event);
+ 	entry->ip = ip;
+ 
+-	len = __copy_from_user_inatomic(&entry->buf, ubuf, cnt);
++	len = copy_from_user_nofault(&entry->buf, ubuf, cnt);
+ 	if (len) {
+ 		memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE);
+ 		cnt = FAULTED_SIZE;
+@@ -7361,7 +7365,7 @@ static ssize_t write_raw_marker_to_buffer(struct trace_array *tr,
+ 
+ 	entry = ring_buffer_event_data(event);
+ 
+-	len = __copy_from_user_inatomic(&entry->id, ubuf, cnt);
++	len = copy_from_user_nofault(&entry->id, ubuf, cnt);
+ 	if (len) {
+ 		entry->id = -1;
+ 		memcpy(&entry->buf, FAULTED_STR, FAULTED_SIZE);
+diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c
+index fd259da0aa6456..337bc0eb5d71bf 100644
+--- a/kernel/trace/trace_osnoise.c
++++ b/kernel/trace/trace_osnoise.c
+@@ -2322,6 +2322,9 @@ osnoise_cpus_write(struct file *filp, const char __user *ubuf, size_t count,
+ 	int running, err;
+ 	char *buf __free(kfree) = NULL;
+ 
++	if (count < 1)
++		return 0;
++
+ 	buf = kmalloc(count, GFP_KERNEL);
+ 	if (!buf)
+ 		return -ENOMEM;
+diff --git a/mm/damon/core.c b/mm/damon/core.c
+index 8ead13792f0495..d87fbb8c418d00 100644
+--- a/mm/damon/core.c
++++ b/mm/damon/core.c
+@@ -2050,6 +2050,10 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
+ 	if (!quota->ms && !quota->sz && list_empty(&quota->goals))
+ 		return;
+ 
++	/* First charge window */
++	if (!quota->total_charged_sz && !quota->charged_from)
++		quota->charged_from = jiffies;
++
+ 	/* New charge window starts */
+ 	if (time_after_eq(jiffies, quota->charged_from +
+ 				msecs_to_jiffies(quota->reset_interval))) {
+diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
+index 4af8fd4a390b66..c2b4f0b0714727 100644
+--- a/mm/damon/lru_sort.c
++++ b/mm/damon/lru_sort.c
+@@ -198,6 +198,11 @@ static int damon_lru_sort_apply_parameters(void)
+ 	if (err)
+ 		return err;
+ 
++	if (!damon_lru_sort_mon_attrs.sample_interval) {
++		err = -EINVAL;
++		goto out;
++	}
++
+ 	err = damon_set_attrs(ctx, &damon_lru_sort_mon_attrs);
+ 	if (err)
+ 		goto out;
+diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
+index a675150965e020..ade3ff724b24cd 100644
+--- a/mm/damon/reclaim.c
++++ b/mm/damon/reclaim.c
+@@ -194,6 +194,11 @@ static int damon_reclaim_apply_parameters(void)
+ 	if (err)
+ 		return err;
+ 
++	if (!damon_reclaim_mon_attrs.aggr_interval) {
++		err = -EINVAL;
++		goto out;
++	}
++
+ 	err = damon_set_attrs(ctx, &damon_reclaim_mon_attrs);
+ 	if (err)
+ 		goto out;
+diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
+index 1af6aff35d84a0..57d4ec256682ce 100644
+--- a/mm/damon/sysfs.c
++++ b/mm/damon/sysfs.c
+@@ -1243,14 +1243,18 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ {
+ 	struct damon_sysfs_kdamond *kdamond = container_of(kobj,
+ 			struct damon_sysfs_kdamond, kobj);
+-	struct damon_ctx *ctx = kdamond->damon_ctx;
+-	bool running;
++	struct damon_ctx *ctx;
++	bool running = false;
+ 
+-	if (!ctx)
+-		running = false;
+-	else
++	if (!mutex_trylock(&damon_sysfs_lock))
++		return -EBUSY;
++
++	ctx = kdamond->damon_ctx;
++	if (ctx)
+ 		running = damon_sysfs_ctx_running(ctx);
+ 
++	mutex_unlock(&damon_sysfs_lock);
++
+ 	return sysfs_emit(buf, "%s\n", running ?
+ 			damon_sysfs_cmd_strs[DAMON_SYSFS_CMD_ON] :
+ 			damon_sysfs_cmd_strs[DAMON_SYSFS_CMD_OFF]);
+diff --git a/mm/hugetlb.c b/mm/hugetlb.c
+index a0d285d2099252..eee833f7068157 100644
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -5855,7 +5855,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ 	spinlock_t *ptl;
+ 	struct hstate *h = hstate_vma(vma);
+ 	unsigned long sz = huge_page_size(h);
+-	bool adjust_reservation = false;
++	bool adjust_reservation;
+ 	unsigned long last_addr_mask;
+ 	bool force_flush = false;
+ 
+@@ -5948,6 +5948,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ 					sz);
+ 		hugetlb_count_sub(pages_per_huge_page(h), mm);
+ 		hugetlb_remove_rmap(folio);
++		spin_unlock(ptl);
+ 
+ 		/*
+ 		 * Restore the reservation for anonymous page, otherwise the
+@@ -5955,14 +5956,16 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+ 		 * If there we are freeing a surplus, do not set the restore
+ 		 * reservation bit.
+ 		 */
++		adjust_reservation = false;
++
++		spin_lock_irq(&hugetlb_lock);
+ 		if (!h->surplus_huge_pages && __vma_private_lock(vma) &&
+ 		    folio_test_anon(folio)) {
+ 			folio_set_hugetlb_restore_reserve(folio);
+ 			/* Reservation to be adjusted after the spin lock */
+ 			adjust_reservation = true;
+ 		}
+-
+-		spin_unlock(ptl);
++		spin_unlock_irq(&hugetlb_lock);
+ 
+ 		/*
+ 		 * Adjust the reservation for the region that will have the
+diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
+index d2c70cd2afb1de..c7c0be11917370 100644
+--- a/mm/kasan/shadow.c
++++ b/mm/kasan/shadow.c
+@@ -335,13 +335,13 @@ static void ___free_pages_bulk(struct page **pages, int nr_pages)
+ 	}
+ }
+ 
+-static int ___alloc_pages_bulk(struct page **pages, int nr_pages)
++static int ___alloc_pages_bulk(struct page **pages, int nr_pages, gfp_t gfp_mask)
+ {
+ 	unsigned long nr_populated, nr_total = nr_pages;
+ 	struct page **page_array = pages;
+ 
+ 	while (nr_pages) {
+-		nr_populated = alloc_pages_bulk(GFP_KERNEL, nr_pages, pages);
++		nr_populated = alloc_pages_bulk(gfp_mask, nr_pages, pages);
+ 		if (!nr_populated) {
+ 			___free_pages_bulk(page_array, nr_total - nr_pages);
+ 			return -ENOMEM;
+@@ -353,25 +353,42 @@ static int ___alloc_pages_bulk(struct page **pages, int nr_pages)
+ 	return 0;
+ }
+ 
+-static int __kasan_populate_vmalloc(unsigned long start, unsigned long end)
++static int __kasan_populate_vmalloc(unsigned long start, unsigned long end, gfp_t gfp_mask)
+ {
+ 	unsigned long nr_pages, nr_total = PFN_UP(end - start);
+ 	struct vmalloc_populate_data data;
++	unsigned int flags;
+ 	int ret = 0;
+ 
+-	data.pages = (struct page **)__get_free_page(GFP_KERNEL | __GFP_ZERO);
++	data.pages = (struct page **)__get_free_page(gfp_mask | __GFP_ZERO);
+ 	if (!data.pages)
+ 		return -ENOMEM;
+ 
+ 	while (nr_total) {
+ 		nr_pages = min(nr_total, PAGE_SIZE / sizeof(data.pages[0]));
+-		ret = ___alloc_pages_bulk(data.pages, nr_pages);
++		ret = ___alloc_pages_bulk(data.pages, nr_pages, gfp_mask);
+ 		if (ret)
+ 			break;
+ 
+ 		data.start = start;
++
++		/*
++		 * page tables allocations ignore external gfp mask, enforce it
++		 * by the scope API
++		 */
++		if ((gfp_mask & (__GFP_FS | __GFP_IO)) == __GFP_IO)
++			flags = memalloc_nofs_save();
++		else if ((gfp_mask & (__GFP_FS | __GFP_IO)) == 0)
++			flags = memalloc_noio_save();
++
+ 		ret = apply_to_page_range(&init_mm, start, nr_pages * PAGE_SIZE,
+ 					  kasan_populate_vmalloc_pte, &data);
++
++		if ((gfp_mask & (__GFP_FS | __GFP_IO)) == __GFP_IO)
++			memalloc_nofs_restore(flags);
++		else if ((gfp_mask & (__GFP_FS | __GFP_IO)) == 0)
++			memalloc_noio_restore(flags);
++
+ 		___free_pages_bulk(data.pages, nr_pages);
+ 		if (ret)
+ 			break;
+@@ -385,7 +402,7 @@ static int __kasan_populate_vmalloc(unsigned long start, unsigned long end)
+ 	return ret;
+ }
+ 
+-int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
++int kasan_populate_vmalloc(unsigned long addr, unsigned long size, gfp_t gfp_mask)
+ {
+ 	unsigned long shadow_start, shadow_end;
+ 	int ret;
+@@ -414,7 +431,7 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
+ 	shadow_start = PAGE_ALIGN_DOWN(shadow_start);
+ 	shadow_end = PAGE_ALIGN(shadow_end);
+ 
+-	ret = __kasan_populate_vmalloc(shadow_start, shadow_end);
++	ret = __kasan_populate_vmalloc(shadow_start, shadow_end, gfp_mask);
+ 	if (ret)
+ 		return ret;
+ 
+diff --git a/mm/khugepaged.c b/mm/khugepaged.c
+index 15203ea7d0073d..a0c040336fc59b 100644
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1400,8 +1400,8 @@ static int hpage_collapse_scan_pmd(struct mm_struct *mm,
+ 		 */
+ 		if (cc->is_khugepaged &&
+ 		    (pte_young(pteval) || folio_test_young(folio) ||
+-		     folio_test_referenced(folio) || mmu_notifier_test_young(vma->vm_mm,
+-								     address)))
++		     folio_test_referenced(folio) ||
++		     mmu_notifier_test_young(vma->vm_mm, _address)))
+ 			referenced++;
+ 	}
+ 	if (!writable) {
+diff --git a/mm/memory-failure.c b/mm/memory-failure.c
+index dd543dd7755fc0..e626b6c93ffeee 100644
+--- a/mm/memory-failure.c
++++ b/mm/memory-failure.c
+@@ -950,7 +950,7 @@ static const char * const action_page_types[] = {
+ 	[MF_MSG_BUDDY]			= "free buddy page",
+ 	[MF_MSG_DAX]			= "dax page",
+ 	[MF_MSG_UNSPLIT_THP]		= "unsplit thp",
+-	[MF_MSG_ALREADY_POISONED]	= "already poisoned",
++	[MF_MSG_ALREADY_POISONED]	= "already poisoned page",
+ 	[MF_MSG_UNKNOWN]		= "unknown page",
+ };
+ 
+@@ -1343,9 +1343,10 @@ static int action_result(unsigned long pfn, enum mf_action_page_type type,
+ {
+ 	trace_memory_failure_event(pfn, type, result);
+ 
+-	num_poisoned_pages_inc(pfn);
+-
+-	update_per_node_mf_stats(pfn, result);
++	if (type != MF_MSG_ALREADY_POISONED) {
++		num_poisoned_pages_inc(pfn);
++		update_per_node_mf_stats(pfn, result);
++	}
+ 
+ 	pr_err("%#lx: recovery action for %s: %s\n",
+ 		pfn, action_page_types[type], action_name[result]);
+@@ -2088,12 +2089,11 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb
+ 		*hugetlb = 0;
+ 		return 0;
+ 	} else if (res == -EHWPOISON) {
+-		pr_err("%#lx: already hardware poisoned\n", pfn);
+ 		if (flags & MF_ACTION_REQUIRED) {
+ 			folio = page_folio(p);
+ 			res = kill_accessing_process(current, folio_pfn(folio), flags);
+-			action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED);
+ 		}
++		action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED);
+ 		return res;
+ 	} else if (res == -EBUSY) {
+ 		if (!(flags & MF_NO_RETRY)) {
+@@ -2279,7 +2279,6 @@ int memory_failure(unsigned long pfn, int flags)
+ 		goto unlock_mutex;
+ 
+ 	if (TestSetPageHWPoison(p)) {
+-		pr_err("%#lx: already hardware poisoned\n", pfn);
+ 		res = -EHWPOISON;
+ 		if (flags & MF_ACTION_REQUIRED)
+ 			res = kill_accessing_process(current, pfn, flags);
+@@ -2576,10 +2575,9 @@ int unpoison_memory(unsigned long pfn)
+ 	static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL,
+ 					DEFAULT_RATELIMIT_BURST);
+ 
+-	if (!pfn_valid(pfn))
+-		return -ENXIO;
+-
+-	p = pfn_to_page(pfn);
++	p = pfn_to_online_page(pfn);
++	if (!p)
++		return -EIO;
+ 	folio = page_folio(p);
+ 
+ 	mutex_lock(&mf_mutex);
+diff --git a/mm/vmalloc.c b/mm/vmalloc.c
+index 6dbcdceecae134..5edd536ba9d2a5 100644
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -2026,6 +2026,8 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
+ 	if (unlikely(!vmap_initialized))
+ 		return ERR_PTR(-EBUSY);
+ 
++	/* Only reclaim behaviour flags are relevant. */
++	gfp_mask = gfp_mask & GFP_RECLAIM_MASK;
+ 	might_sleep();
+ 
+ 	/*
+@@ -2038,8 +2040,6 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
+ 	 */
+ 	va = node_alloc(size, align, vstart, vend, &addr, &vn_id);
+ 	if (!va) {
+-		gfp_mask = gfp_mask & GFP_RECLAIM_MASK;
+-
+ 		va = kmem_cache_alloc_node(vmap_area_cachep, gfp_mask, node);
+ 		if (unlikely(!va))
+ 			return ERR_PTR(-ENOMEM);
+@@ -2089,7 +2089,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
+ 	BUG_ON(va->va_start < vstart);
+ 	BUG_ON(va->va_end > vend);
+ 
+-	ret = kasan_populate_vmalloc(addr, size);
++	ret = kasan_populate_vmalloc(addr, size, gfp_mask);
+ 	if (ret) {
+ 		free_vmap_area(va);
+ 		return ERR_PTR(ret);
+@@ -4826,7 +4826,7 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
+ 
+ 	/* populate the kasan shadow space */
+ 	for (area = 0; area < nr_vms; area++) {
+-		if (kasan_populate_vmalloc(vas[area]->va_start, sizes[area]))
++		if (kasan_populate_vmalloc(vas[area]->va_start, sizes[area], GFP_KERNEL))
+ 			goto err_free_shadow;
+ 	}
+ 
+diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
+index ad5574e9a93ee9..ce17e489c67c37 100644
+--- a/net/bluetooth/hci_conn.c
++++ b/net/bluetooth/hci_conn.c
+@@ -829,7 +829,17 @@ static void bis_cleanup(struct hci_conn *conn)
+ 		/* Check if ISO connection is a BIS and terminate advertising
+ 		 * set and BIG if there are no other connections using it.
+ 		 */
+-		bis = hci_conn_hash_lookup_big(hdev, conn->iso_qos.bcast.big);
++		bis = hci_conn_hash_lookup_big_state(hdev,
++						     conn->iso_qos.bcast.big,
++						     BT_CONNECTED,
++						     HCI_ROLE_MASTER);
++		if (bis)
++			return;
++
++		bis = hci_conn_hash_lookup_big_state(hdev,
++						     conn->iso_qos.bcast.big,
++						     BT_CONNECT,
++						     HCI_ROLE_MASTER);
+ 		if (bis)
+ 			return;
+ 
+@@ -2274,7 +2284,7 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
+ 	 * the start periodic advertising and create BIG commands have
+ 	 * been queued
+ 	 */
+-	hci_conn_hash_list_state(hdev, bis_mark_per_adv, PA_LINK,
++	hci_conn_hash_list_state(hdev, bis_mark_per_adv, BIS_LINK,
+ 				 BT_BOUND, &data);
+ 
+ 	/* Queue start periodic advertising and create BIG */
+diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
+index 0ffdbe249f5d3d..090c7ffa515252 100644
+--- a/net/bluetooth/hci_event.c
++++ b/net/bluetooth/hci_event.c
+@@ -6973,9 +6973,14 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
+ 				continue;
+ 		}
+ 
+-		if (ev->status != 0x42)
++		if (ev->status != 0x42) {
+ 			/* Mark PA sync as established */
+ 			set_bit(HCI_CONN_PA_SYNC, &bis->flags);
++			/* Reset cleanup callback of PA Sync so it doesn't
++			 * terminate the sync when deleting the connection.
++			 */
++			conn->cleanup = NULL;
++		}
+ 
+ 		bis->sync_handle = conn->sync_handle;
+ 		bis->iso_qos.bcast.big = ev->handle;
+diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
+index 14a4215352d5f1..c21566e1494a99 100644
+--- a/net/bluetooth/iso.c
++++ b/net/bluetooth/iso.c
+@@ -1347,7 +1347,7 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,
+ 		bacpy(&sa->iso_bdaddr, &iso_pi(sk)->dst);
+ 		sa->iso_bdaddr_type = iso_pi(sk)->dst_type;
+ 
+-		if (hcon && hcon->type == BIS_LINK) {
++		if (hcon && (hcon->type == BIS_LINK || hcon->type == PA_LINK)) {
+ 			sa->iso_bc->bc_sid = iso_pi(sk)->bc_sid;
+ 			sa->iso_bc->bc_num_bis = iso_pi(sk)->bc_num_bis;
+ 			memcpy(sa->iso_bc->bc_bis, iso_pi(sk)->bc_bis,
+diff --git a/net/bridge/br.c b/net/bridge/br.c
+index 0adeafe11a3651..ad2d8f59fc7bcc 100644
+--- a/net/bridge/br.c
++++ b/net/bridge/br.c
+@@ -324,6 +324,13 @@ int br_boolopt_multi_toggle(struct net_bridge *br,
+ 	int err = 0;
+ 	int opt_id;
+ 
++	opt_id = find_next_bit(&bitmap, BITS_PER_LONG, BR_BOOLOPT_MAX);
++	if (opt_id != BITS_PER_LONG) {
++		NL_SET_ERR_MSG_FMT_MOD(extack, "Unknown boolean option %d",
++				       opt_id);
++		return -EINVAL;
++	}
++
+ 	for_each_set_bit(opt_id, &bitmap, BR_BOOLOPT_MAX) {
+ 		bool on = !!(bm->optval & BIT(opt_id));
+ 
+diff --git a/net/can/j1939/bus.c b/net/can/j1939/bus.c
+index 39844f14eed862..797719cb227ec5 100644
+--- a/net/can/j1939/bus.c
++++ b/net/can/j1939/bus.c
+@@ -290,8 +290,11 @@ int j1939_local_ecu_get(struct j1939_priv *priv, name_t name, u8 sa)
+ 	if (!ecu)
+ 		ecu = j1939_ecu_create_locked(priv, name);
+ 	err = PTR_ERR_OR_ZERO(ecu);
+-	if (err)
++	if (err) {
++		if (j1939_address_is_unicast(sa))
++			priv->ents[sa].nusers--;
+ 		goto done;
++	}
+ 
+ 	ecu->nusers++;
+ 	/* TODO: do we care if ecu->addr != sa? */
+diff --git a/net/can/j1939/j1939-priv.h b/net/can/j1939/j1939-priv.h
+index 31a93cae5111b5..81f58924b4acd7 100644
+--- a/net/can/j1939/j1939-priv.h
++++ b/net/can/j1939/j1939-priv.h
+@@ -212,6 +212,7 @@ void j1939_priv_get(struct j1939_priv *priv);
+ 
+ /* notify/alert all j1939 sockets bound to ifindex */
+ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv);
++void j1939_sk_netdev_event_unregister(struct j1939_priv *priv);
+ int j1939_cancel_active_session(struct j1939_priv *priv, struct sock *sk);
+ void j1939_tp_init(struct j1939_priv *priv);
+ 
+diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c
+index 7e8a20f2fc42b5..3706a872ecafdb 100644
+--- a/net/can/j1939/main.c
++++ b/net/can/j1939/main.c
+@@ -377,6 +377,9 @@ static int j1939_netdev_notify(struct notifier_block *nb,
+ 		j1939_sk_netdev_event_netdown(priv);
+ 		j1939_ecu_unmap_all(priv);
+ 		break;
++	case NETDEV_UNREGISTER:
++		j1939_sk_netdev_event_unregister(priv);
++		break;
+ 	}
+ 
+ 	j1939_priv_put(priv);
+diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c
+index 6fefe7a6876116..785b883a1319d3 100644
+--- a/net/can/j1939/socket.c
++++ b/net/can/j1939/socket.c
+@@ -520,6 +520,9 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
+ 	ret = j1939_local_ecu_get(priv, jsk->addr.src_name, jsk->addr.sa);
+ 	if (ret) {
+ 		j1939_netdev_stop(priv);
++		jsk->priv = NULL;
++		synchronize_rcu();
++		j1939_priv_put(priv);
+ 		goto out_release_sock;
+ 	}
+ 
+@@ -1299,6 +1302,55 @@ void j1939_sk_netdev_event_netdown(struct j1939_priv *priv)
+ 	read_unlock_bh(&priv->j1939_socks_lock);
+ }
+ 
++void j1939_sk_netdev_event_unregister(struct j1939_priv *priv)
++{
++	struct sock *sk;
++	struct j1939_sock *jsk;
++	bool wait_rcu = false;
++
++rescan: /* The caller is holding a ref on this "priv" via j1939_priv_get_by_ndev(). */
++	read_lock_bh(&priv->j1939_socks_lock);
++	list_for_each_entry(jsk, &priv->j1939_socks, list) {
++		/* Skip if j1939_jsk_add() is not called on this socket. */
++		if (!(jsk->state & J1939_SOCK_BOUND))
++			continue;
++		sk = &jsk->sk;
++		sock_hold(sk);
++		read_unlock_bh(&priv->j1939_socks_lock);
++		/* Check if j1939_jsk_del() is not yet called on this socket after holding
++		 * socket's lock, for both j1939_sk_bind() and j1939_sk_release() call
++		 * j1939_jsk_del() with socket's lock held.
++		 */
++		lock_sock(sk);
++		if (jsk->state & J1939_SOCK_BOUND) {
++			/* Neither j1939_sk_bind() nor j1939_sk_release() called j1939_jsk_del().
++			 * Make this socket no longer bound, by pretending as if j1939_sk_bind()
++			 * dropped old references but did not get new references.
++			 */
++			j1939_jsk_del(priv, jsk);
++			j1939_local_ecu_put(priv, jsk->addr.src_name, jsk->addr.sa);
++			j1939_netdev_stop(priv);
++			/* Call j1939_priv_put() now and prevent j1939_sk_sock_destruct() from
++			 * calling the corresponding j1939_priv_put().
++			 *
++			 * j1939_sk_sock_destruct() is supposed to call j1939_priv_put() after
++			 * an RCU grace period. But since the caller is holding a ref on this
++			 * "priv", we can defer synchronize_rcu() until immediately before
++			 * the caller calls j1939_priv_put().
++			 */
++			j1939_priv_put(priv);
++			jsk->priv = NULL;
++			wait_rcu = true;
++		}
++		release_sock(sk);
++		sock_put(sk);
++		goto rescan;
++	}
++	read_unlock_bh(&priv->j1939_socks_lock);
++	if (wait_rcu)
++		synchronize_rcu();
++}
++
+ static int j1939_sk_no_ioctlcmd(struct socket *sock, unsigned int cmd,
+ 				unsigned long arg)
+ {
+diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
+index d1b5705dc0c648..9f6d860411cbd1 100644
+--- a/net/ceph/messenger.c
++++ b/net/ceph/messenger.c
+@@ -1524,7 +1524,7 @@ static void con_fault_finish(struct ceph_connection *con)
+ 	 * in case we faulted due to authentication, invalidate our
+ 	 * current tickets so that we can get new ones.
+ 	 */
+-	if (con->v1.auth_retry) {
++	if (!ceph_msgr2(from_msgr(con->msgr)) && con->v1.auth_retry) {
+ 		dout("auth_retry %d, invalidating\n", con->v1.auth_retry);
+ 		if (con->ops->invalidate_authorizer)
+ 			con->ops->invalidate_authorizer(con);
+@@ -1714,9 +1714,10 @@ static void clear_standby(struct ceph_connection *con)
+ {
+ 	/* come back from STANDBY? */
+ 	if (con->state == CEPH_CON_S_STANDBY) {
+-		dout("clear_standby %p and ++connect_seq\n", con);
++		dout("clear_standby %p\n", con);
+ 		con->state = CEPH_CON_S_PREOPEN;
+-		con->v1.connect_seq++;
++		if (!ceph_msgr2(from_msgr(con->msgr)))
++			con->v1.connect_seq++;
+ 		WARN_ON(ceph_con_flag_test(con, CEPH_CON_F_WRITE_PENDING));
+ 		WARN_ON(ceph_con_flag_test(con, CEPH_CON_F_KEEPALIVE_PENDING));
+ 	}
+diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
+index 616479e7146633..9447065d01afb0 100644
+--- a/net/core/dev_ioctl.c
++++ b/net/core/dev_ioctl.c
+@@ -464,8 +464,15 @@ int generic_hwtstamp_get_lower(struct net_device *dev,
+ 	if (!netif_device_present(dev))
+ 		return -ENODEV;
+ 
+-	if (ops->ndo_hwtstamp_get)
+-		return dev_get_hwtstamp_phylib(dev, kernel_cfg);
++	if (ops->ndo_hwtstamp_get) {
++		int err;
++
++		netdev_lock_ops(dev);
++		err = dev_get_hwtstamp_phylib(dev, kernel_cfg);
++		netdev_unlock_ops(dev);
++
++		return err;
++	}
+ 
+ 	/* Legacy path: unconverted lower driver */
+ 	return generic_hwtstamp_ioctl_lower(dev, SIOCGHWTSTAMP, kernel_cfg);
+@@ -481,8 +488,15 @@ int generic_hwtstamp_set_lower(struct net_device *dev,
+ 	if (!netif_device_present(dev))
+ 		return -ENODEV;
+ 
+-	if (ops->ndo_hwtstamp_set)
+-		return dev_set_hwtstamp_phylib(dev, kernel_cfg, extack);
++	if (ops->ndo_hwtstamp_set) {
++		int err;
++
++		netdev_lock_ops(dev);
++		err = dev_set_hwtstamp_phylib(dev, kernel_cfg, extack);
++		netdev_unlock_ops(dev);
++
++		return err;
++	}
+ 
+ 	/* Legacy path: unconverted lower driver */
+ 	return generic_hwtstamp_ioctl_lower(dev, SIOCSHWTSTAMP, kernel_cfg);
+diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
+index 88657255fec12b..fbbc3ccf9df64b 100644
+--- a/net/hsr/hsr_device.c
++++ b/net/hsr/hsr_device.c
+@@ -49,7 +49,7 @@ static bool hsr_check_carrier(struct hsr_port *master)
+ 
+ 	ASSERT_RTNL();
+ 
+-	hsr_for_each_port(master->hsr, port) {
++	hsr_for_each_port_rtnl(master->hsr, port) {
+ 		if (port->type != HSR_PT_MASTER && is_slave_up(port->dev)) {
+ 			netif_carrier_on(master->dev);
+ 			return true;
+@@ -105,7 +105,7 @@ int hsr_get_max_mtu(struct hsr_priv *hsr)
+ 	struct hsr_port *port;
+ 
+ 	mtu_max = ETH_DATA_LEN;
+-	hsr_for_each_port(hsr, port)
++	hsr_for_each_port_rtnl(hsr, port)
+ 		if (port->type != HSR_PT_MASTER)
+ 			mtu_max = min(port->dev->mtu, mtu_max);
+ 
+@@ -139,7 +139,7 @@ static int hsr_dev_open(struct net_device *dev)
+ 
+ 	hsr = netdev_priv(dev);
+ 
+-	hsr_for_each_port(hsr, port) {
++	hsr_for_each_port_rtnl(hsr, port) {
+ 		if (port->type == HSR_PT_MASTER)
+ 			continue;
+ 		switch (port->type) {
+@@ -172,7 +172,7 @@ static int hsr_dev_close(struct net_device *dev)
+ 	struct hsr_priv *hsr;
+ 
+ 	hsr = netdev_priv(dev);
+-	hsr_for_each_port(hsr, port) {
++	hsr_for_each_port_rtnl(hsr, port) {
+ 		if (port->type == HSR_PT_MASTER)
+ 			continue;
+ 		switch (port->type) {
+@@ -205,7 +205,7 @@ static netdev_features_t hsr_features_recompute(struct hsr_priv *hsr,
+ 	 * may become enabled.
+ 	 */
+ 	features &= ~NETIF_F_ONE_FOR_ALL;
+-	hsr_for_each_port(hsr, port)
++	hsr_for_each_port_rtnl(hsr, port)
+ 		features = netdev_increment_features(features,
+ 						     port->dev->features,
+ 						     mask);
+@@ -226,6 +226,7 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+ 	struct hsr_priv *hsr = netdev_priv(dev);
+ 	struct hsr_port *master;
+ 
++	rcu_read_lock();
+ 	master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
+ 	if (master) {
+ 		skb->dev = master->dev;
+@@ -238,6 +239,8 @@ static netdev_tx_t hsr_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+ 		dev_core_stats_tx_dropped_inc(dev);
+ 		dev_kfree_skb_any(skb);
+ 	}
++	rcu_read_unlock();
++
+ 	return NETDEV_TX_OK;
+ }
+ 
+@@ -484,7 +487,7 @@ static void hsr_set_rx_mode(struct net_device *dev)
+ 
+ 	hsr = netdev_priv(dev);
+ 
+-	hsr_for_each_port(hsr, port) {
++	hsr_for_each_port_rtnl(hsr, port) {
+ 		if (port->type == HSR_PT_MASTER)
+ 			continue;
+ 		switch (port->type) {
+@@ -506,7 +509,7 @@ static void hsr_change_rx_flags(struct net_device *dev, int change)
+ 
+ 	hsr = netdev_priv(dev);
+ 
+-	hsr_for_each_port(hsr, port) {
++	hsr_for_each_port_rtnl(hsr, port) {
+ 		if (port->type == HSR_PT_MASTER)
+ 			continue;
+ 		switch (port->type) {
+@@ -534,7 +537,7 @@ static int hsr_ndo_vlan_rx_add_vid(struct net_device *dev,
+ 
+ 	hsr = netdev_priv(dev);
+ 
+-	hsr_for_each_port(hsr, port) {
++	hsr_for_each_port_rtnl(hsr, port) {
+ 		if (port->type == HSR_PT_MASTER ||
+ 		    port->type == HSR_PT_INTERLINK)
+ 			continue;
+@@ -580,7 +583,7 @@ static int hsr_ndo_vlan_rx_kill_vid(struct net_device *dev,
+ 
+ 	hsr = netdev_priv(dev);
+ 
+-	hsr_for_each_port(hsr, port) {
++	hsr_for_each_port_rtnl(hsr, port) {
+ 		switch (port->type) {
+ 		case HSR_PT_SLAVE_A:
+ 		case HSR_PT_SLAVE_B:
+@@ -672,9 +675,14 @@ struct net_device *hsr_get_port_ndev(struct net_device *ndev,
+ 	struct hsr_priv *hsr = netdev_priv(ndev);
+ 	struct hsr_port *port;
+ 
++	rcu_read_lock();
+ 	hsr_for_each_port(hsr, port)
+-		if (port->type == pt)
++		if (port->type == pt) {
++			dev_hold(port->dev);
++			rcu_read_unlock();
+ 			return port->dev;
++		}
++	rcu_read_unlock();
+ 	return NULL;
+ }
+ EXPORT_SYMBOL(hsr_get_port_ndev);
+diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c
+index 192893c3f2ec73..bc94b07101d80e 100644
+--- a/net/hsr/hsr_main.c
++++ b/net/hsr/hsr_main.c
+@@ -22,7 +22,7 @@ static bool hsr_slave_empty(struct hsr_priv *hsr)
+ {
+ 	struct hsr_port *port;
+ 
+-	hsr_for_each_port(hsr, port)
++	hsr_for_each_port_rtnl(hsr, port)
+ 		if (port->type != HSR_PT_MASTER)
+ 			return false;
+ 	return true;
+@@ -134,7 +134,7 @@ struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt)
+ {
+ 	struct hsr_port *port;
+ 
+-	hsr_for_each_port(hsr, port)
++	hsr_for_each_port_rtnl(hsr, port)
+ 		if (port->type == pt)
+ 			return port;
+ 	return NULL;
+diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
+index 135ec5fce01967..33b0d2460c9bcd 100644
+--- a/net/hsr/hsr_main.h
++++ b/net/hsr/hsr_main.h
+@@ -224,6 +224,9 @@ struct hsr_priv {
+ #define hsr_for_each_port(hsr, port) \
+ 	list_for_each_entry_rcu((port), &(hsr)->ports, port_list)
+ 
++#define hsr_for_each_port_rtnl(hsr, port) \
++	list_for_each_entry_rcu((port), &(hsr)->ports, port_list, lockdep_rtnl_is_held())
++
+ struct hsr_port *hsr_port_get_hsr(struct hsr_priv *hsr, enum hsr_port_type pt);
+ 
+ /* Caller must ensure skb is a valid HSR frame */
+diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
+index f65d2f7273813b..8392d304a72ebe 100644
+--- a/net/ipv4/ip_tunnel_core.c
++++ b/net/ipv4/ip_tunnel_core.c
+@@ -204,6 +204,9 @@ static int iptunnel_pmtud_build_icmp(struct sk_buff *skb, int mtu)
+ 	if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr)))
+ 		return -EINVAL;
+ 
++	if (skb_is_gso(skb))
++		skb_gso_reset(skb);
++
+ 	skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
+ 	pskb_pull(skb, ETH_HLEN);
+ 	skb_reset_network_header(skb);
+@@ -298,6 +301,9 @@ static int iptunnel_pmtud_build_icmpv6(struct sk_buff *skb, int mtu)
+ 	if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr)))
+ 		return -EINVAL;
+ 
++	if (skb_is_gso(skb))
++		skb_gso_reset(skb);
++
+ 	skb_copy_bits(skb, skb_mac_offset(skb), &eh, ETH_HLEN);
+ 	pskb_pull(skb, ETH_HLEN);
+ 	skb_reset_network_header(skb);
+diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
+index ba581785adb4b3..a268e1595b22aa 100644
+--- a/net/ipv4/tcp_bpf.c
++++ b/net/ipv4/tcp_bpf.c
+@@ -408,8 +408,11 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
+ 		if (!psock->cork) {
+ 			psock->cork = kzalloc(sizeof(*psock->cork),
+ 					      GFP_ATOMIC | __GFP_NOWARN);
+-			if (!psock->cork)
++			if (!psock->cork) {
++				sk_msg_free(sk, msg);
++				*copied = 0;
+ 				return -ENOMEM;
++			}
+ 		}
+ 		memcpy(psock->cork, msg, sizeof(*msg));
+ 		return 0;
+diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
+index 3caa0a9d3b3885..25d2b65653cd40 100644
+--- a/net/mptcp/sockopt.c
++++ b/net/mptcp/sockopt.c
+@@ -1508,13 +1508,12 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
+ {
+ 	static const unsigned int tx_rx_locks = SOCK_RCVBUF_LOCK | SOCK_SNDBUF_LOCK;
+ 	struct sock *sk = (struct sock *)msk;
++	bool keep_open;
+ 
+-	if (ssk->sk_prot->keepalive) {
+-		if (sock_flag(sk, SOCK_KEEPOPEN))
+-			ssk->sk_prot->keepalive(ssk, 1);
+-		else
+-			ssk->sk_prot->keepalive(ssk, 0);
+-	}
++	keep_open = sock_flag(sk, SOCK_KEEPOPEN);
++	if (ssk->sk_prot->keepalive)
++		ssk->sk_prot->keepalive(ssk, keep_open);
++	sock_valbool_flag(ssk, SOCK_KEEPOPEN, keep_open);
+ 
+ 	ssk->sk_priority = sk->sk_priority;
+ 	ssk->sk_bound_dev_if = sk->sk_bound_dev_if;
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 0e86434ca13b00..cde63e5f18d8f9 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -1131,11 +1131,14 @@ nf_tables_chain_type_lookup(struct net *net, const struct nlattr *nla,
+ 	return ERR_PTR(-ENOENT);
+ }
+ 
+-static __be16 nft_base_seq(const struct net *net)
++static unsigned int nft_base_seq(const struct net *net)
+ {
+-	struct nftables_pernet *nft_net = nft_pernet(net);
++	return READ_ONCE(net->nft.base_seq);
++}
+ 
+-	return htons(nft_net->base_seq & 0xffff);
++static __be16 nft_base_seq_be16(const struct net *net)
++{
++	return htons(nft_base_seq(net) & 0xffff);
+ }
+ 
+ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
+@@ -1153,9 +1156,9 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
+ {
+ 	struct nlmsghdr *nlh;
+ 
+-	event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-	nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+-			   NFNETLINK_V0, nft_base_seq(net));
++	nlh = nfnl_msg_put(skb, portid, seq,
++			   nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event),
++			   flags, family, NFNETLINK_V0, nft_base_seq_be16(net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+@@ -1165,6 +1168,12 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
+ 			 NFTA_TABLE_PAD))
+ 		goto nla_put_failure;
+ 
++	if (event == NFT_MSG_DELTABLE ||
++	    event == NFT_MSG_DESTROYTABLE) {
++		nlmsg_end(skb, nlh);
++		return 0;
++	}
++
+ 	if (nla_put_be32(skb, NFTA_TABLE_FLAGS,
+ 			 htonl(table->flags & NFT_TABLE_F_MASK)))
+ 		goto nla_put_failure;
+@@ -1242,7 +1251,7 @@ static int nf_tables_dump_tables(struct sk_buff *skb,
+ 
+ 	rcu_read_lock();
+ 	nft_net = nft_pernet(net);
+-	cb->seq = READ_ONCE(nft_net->base_seq);
++	cb->seq = nft_base_seq(net);
+ 
+ 	list_for_each_entry_rcu(table, &nft_net->tables, list) {
+ 		if (family != NFPROTO_UNSPEC && family != table->family)
+@@ -2022,9 +2031,9 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
+ {
+ 	struct nlmsghdr *nlh;
+ 
+-	event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-	nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+-			   NFNETLINK_V0, nft_base_seq(net));
++	nlh = nfnl_msg_put(skb, portid, seq,
++			   nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event),
++			   flags, family, NFNETLINK_V0, nft_base_seq_be16(net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+@@ -2034,6 +2043,13 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
+ 			 NFTA_CHAIN_PAD))
+ 		goto nla_put_failure;
+ 
++	if (!hook_list &&
++	    (event == NFT_MSG_DELCHAIN ||
++	     event == NFT_MSG_DESTROYCHAIN)) {
++		nlmsg_end(skb, nlh);
++		return 0;
++	}
++
+ 	if (nft_is_base_chain(chain)) {
+ 		const struct nft_base_chain *basechain = nft_base_chain(chain);
+ 		struct nft_stats __percpu *stats;
+@@ -2120,7 +2136,7 @@ static int nf_tables_dump_chains(struct sk_buff *skb,
+ 
+ 	rcu_read_lock();
+ 	nft_net = nft_pernet(net);
+-	cb->seq = READ_ONCE(nft_net->base_seq);
++	cb->seq = nft_base_seq(net);
+ 
+ 	list_for_each_entry_rcu(table, &nft_net->tables, list) {
+ 		if (family != NFPROTO_UNSPEC && family != table->family)
+@@ -3658,7 +3674,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
+ 	u16 type = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+ 
+ 	nlh = nfnl_msg_put(skb, portid, seq, type, flags, family, NFNETLINK_V0,
+-			   nft_base_seq(net));
++			   nft_base_seq_be16(net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+@@ -3826,7 +3842,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
+ 
+ 	rcu_read_lock();
+ 	nft_net = nft_pernet(net);
+-	cb->seq = READ_ONCE(nft_net->base_seq);
++	cb->seq = nft_base_seq(net);
+ 
+ 	list_for_each_entry_rcu(table, &nft_net->tables, list) {
+ 		if (family != NFPROTO_UNSPEC && family != table->family)
+@@ -4037,7 +4053,7 @@ static int nf_tables_getrule_reset(struct sk_buff *skb,
+ 	buf = kasprintf(GFP_ATOMIC, "%.*s:%u",
+ 			nla_len(nla[NFTA_RULE_TABLE]),
+ 			(char *)nla_data(nla[NFTA_RULE_TABLE]),
+-			nft_net->base_seq);
++			nft_base_seq(net));
+ 	audit_log_nfcfg(buf, info->nfmsg->nfgen_family, 1,
+ 			AUDIT_NFT_OP_RULE_RESET, GFP_ATOMIC);
+ 	kfree(buf);
+@@ -4871,9 +4887,10 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
+ 	u32 seq = ctx->seq;
+ 	int i;
+ 
+-	event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-	nlh = nfnl_msg_put(skb, portid, seq, event, flags, ctx->family,
+-			   NFNETLINK_V0, nft_base_seq(ctx->net));
++	nlh = nfnl_msg_put(skb, portid, seq,
++			   nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event),
++			   flags, ctx->family, NFNETLINK_V0,
++			   nft_base_seq_be16(ctx->net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+@@ -4885,6 +4902,12 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
+ 			 NFTA_SET_PAD))
+ 		goto nla_put_failure;
+ 
++	if (event == NFT_MSG_DELSET ||
++	    event == NFT_MSG_DESTROYSET) {
++		nlmsg_end(skb, nlh);
++		return 0;
++	}
++
+ 	if (set->flags != 0)
+ 		if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
+ 			goto nla_put_failure;
+@@ -5012,7 +5035,7 @@ static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
+ 
+ 	rcu_read_lock();
+ 	nft_net = nft_pernet(net);
+-	cb->seq = READ_ONCE(nft_net->base_seq);
++	cb->seq = nft_base_seq(net);
+ 
+ 	list_for_each_entry_rcu(table, &nft_net->tables, list) {
+ 		if (ctx->family != NFPROTO_UNSPEC &&
+@@ -6189,7 +6212,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
+ 
+ 	rcu_read_lock();
+ 	nft_net = nft_pernet(net);
+-	cb->seq = READ_ONCE(nft_net->base_seq);
++	cb->seq = nft_base_seq(net);
+ 
+ 	list_for_each_entry_rcu(table, &nft_net->tables, list) {
+ 		if (dump_ctx->ctx.family != NFPROTO_UNSPEC &&
+@@ -6218,7 +6241,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
+ 	seq    = cb->nlh->nlmsg_seq;
+ 
+ 	nlh = nfnl_msg_put(skb, portid, seq, event, NLM_F_MULTI,
+-			   table->family, NFNETLINK_V0, nft_base_seq(net));
++			   table->family, NFNETLINK_V0, nft_base_seq_be16(net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+@@ -6311,7 +6334,7 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb,
+ 
+ 	event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+ 	nlh = nfnl_msg_put(skb, portid, seq, event, flags, ctx->family,
+-			   NFNETLINK_V0, nft_base_seq(ctx->net));
++			   NFNETLINK_V0, nft_base_seq_be16(ctx->net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+@@ -6610,7 +6633,7 @@ static int nf_tables_getsetelem_reset(struct sk_buff *skb,
+ 		}
+ 		nelems++;
+ 	}
+-	audit_log_nft_set_reset(dump_ctx.ctx.table, nft_net->base_seq, nelems);
++	audit_log_nft_set_reset(dump_ctx.ctx.table, nft_base_seq(info->net), nelems);
+ 
+ out_unlock:
+ 	rcu_read_unlock();
+@@ -8359,20 +8382,26 @@ static int nf_tables_fill_obj_info(struct sk_buff *skb, struct net *net,
+ {
+ 	struct nlmsghdr *nlh;
+ 
+-	event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-	nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+-			   NFNETLINK_V0, nft_base_seq(net));
++	nlh = nfnl_msg_put(skb, portid, seq,
++			   nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event),
++			   flags, family, NFNETLINK_V0, nft_base_seq_be16(net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+ 	if (nla_put_string(skb, NFTA_OBJ_TABLE, table->name) ||
+ 	    nla_put_string(skb, NFTA_OBJ_NAME, obj->key.name) ||
++	    nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
+ 	    nla_put_be64(skb, NFTA_OBJ_HANDLE, cpu_to_be64(obj->handle),
+ 			 NFTA_OBJ_PAD))
+ 		goto nla_put_failure;
+ 
+-	if (nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
+-	    nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
++	if (event == NFT_MSG_DELOBJ ||
++	    event == NFT_MSG_DESTROYOBJ) {
++		nlmsg_end(skb, nlh);
++		return 0;
++	}
++
++	if (nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
+ 	    nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
+ 		goto nla_put_failure;
+ 
+@@ -8420,7 +8449,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
+ 
+ 	rcu_read_lock();
+ 	nft_net = nft_pernet(net);
+-	cb->seq = READ_ONCE(nft_net->base_seq);
++	cb->seq = nft_base_seq(net);
+ 
+ 	list_for_each_entry_rcu(table, &nft_net->tables, list) {
+ 		if (family != NFPROTO_UNSPEC && family != table->family)
+@@ -8454,7 +8483,7 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
+ 			idx++;
+ 		}
+ 		if (ctx->reset && entries)
+-			audit_log_obj_reset(table, nft_net->base_seq, entries);
++			audit_log_obj_reset(table, nft_base_seq(net), entries);
+ 		if (rc < 0)
+ 			break;
+ 	}
+@@ -8623,7 +8652,7 @@ static int nf_tables_getobj_reset(struct sk_buff *skb,
+ 	buf = kasprintf(GFP_ATOMIC, "%.*s:%u",
+ 			nla_len(nla[NFTA_OBJ_TABLE]),
+ 			(char *)nla_data(nla[NFTA_OBJ_TABLE]),
+-			nft_net->base_seq);
++			nft_base_seq(net));
+ 	audit_log_nfcfg(buf, info->nfmsg->nfgen_family, 1,
+ 			AUDIT_NFT_OP_OBJ_RESET, GFP_ATOMIC);
+ 	kfree(buf);
+@@ -8728,9 +8757,8 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
+ 		    struct nft_object *obj, u32 portid, u32 seq, int event,
+ 		    u16 flags, int family, int report, gfp_t gfp)
+ {
+-	struct nftables_pernet *nft_net = nft_pernet(net);
+ 	char *buf = kasprintf(gfp, "%s:%u",
+-			      table->name, nft_net->base_seq);
++			      table->name, nft_base_seq(net));
+ 
+ 	audit_log_nfcfg(buf,
+ 			family,
+@@ -9413,9 +9441,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
+ 	struct nft_hook *hook;
+ 	struct nlmsghdr *nlh;
+ 
+-	event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-	nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+-			   NFNETLINK_V0, nft_base_seq(net));
++	nlh = nfnl_msg_put(skb, portid, seq,
++			   nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event),
++			   flags, family, NFNETLINK_V0, nft_base_seq_be16(net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+@@ -9425,6 +9453,13 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
+ 			 NFTA_FLOWTABLE_PAD))
+ 		goto nla_put_failure;
+ 
++	if (!hook_list &&
++	    (event == NFT_MSG_DELFLOWTABLE ||
++	     event == NFT_MSG_DESTROYFLOWTABLE)) {
++		nlmsg_end(skb, nlh);
++		return 0;
++	}
++
+ 	if (nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
+ 	    nla_put_be32(skb, NFTA_FLOWTABLE_FLAGS, htonl(flowtable->data.flags)))
+ 		goto nla_put_failure;
+@@ -9477,7 +9512,7 @@ static int nf_tables_dump_flowtable(struct sk_buff *skb,
+ 
+ 	rcu_read_lock();
+ 	nft_net = nft_pernet(net);
+-	cb->seq = READ_ONCE(nft_net->base_seq);
++	cb->seq = nft_base_seq(net);
+ 
+ 	list_for_each_entry_rcu(table, &nft_net->tables, list) {
+ 		if (family != NFPROTO_UNSPEC && family != table->family)
+@@ -9662,17 +9697,16 @@ static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
+ static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
+ 				   u32 portid, u32 seq)
+ {
+-	struct nftables_pernet *nft_net = nft_pernet(net);
+ 	struct nlmsghdr *nlh;
+ 	char buf[TASK_COMM_LEN];
+ 	int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
+ 
+ 	nlh = nfnl_msg_put(skb, portid, seq, event, 0, AF_UNSPEC,
+-			   NFNETLINK_V0, nft_base_seq(net));
++			   NFNETLINK_V0, nft_base_seq_be16(net));
+ 	if (!nlh)
+ 		goto nla_put_failure;
+ 
+-	if (nla_put_be32(skb, NFTA_GEN_ID, htonl(nft_net->base_seq)) ||
++	if (nla_put_be32(skb, NFTA_GEN_ID, htonl(nft_base_seq(net))) ||
+ 	    nla_put_be32(skb, NFTA_GEN_PROC_PID, htonl(task_pid_nr(current))) ||
+ 	    nla_put_string(skb, NFTA_GEN_PROC_NAME, get_task_comm(buf, current)))
+ 		goto nla_put_failure;
+@@ -10933,11 +10967,12 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
+ 	 * Bump generation counter, invalidate any dump in progress.
+ 	 * Cannot fail after this point.
+ 	 */
+-	base_seq = READ_ONCE(nft_net->base_seq);
++	base_seq = nft_base_seq(net);
+ 	while (++base_seq == 0)
+ 		;
+ 
+-	WRITE_ONCE(nft_net->base_seq, base_seq);
++	/* pairs with smp_load_acquire in nft_lookup_eval */
++	smp_store_release(&net->nft.base_seq, base_seq);
+ 
+ 	gc_seq = nft_gc_seq_begin(nft_net);
+ 
+@@ -11146,7 +11181,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
+ 
+ 	nft_commit_notify(net, NETLINK_CB(skb).portid);
+ 	nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
+-	nf_tables_commit_audit_log(&adl, nft_net->base_seq);
++	nf_tables_commit_audit_log(&adl, nft_base_seq(net));
+ 
+ 	nft_gc_seq_end(nft_net, gc_seq);
+ 	nft_net->validate_state = NFT_VALIDATE_SKIP;
+@@ -11471,7 +11506,7 @@ static bool nf_tables_valid_genid(struct net *net, u32 genid)
+ 	mutex_lock(&nft_net->commit_mutex);
+ 	nft_net->tstamp = get_jiffies_64();
+ 
+-	genid_ok = genid == 0 || nft_net->base_seq == genid;
++	genid_ok = genid == 0 || nft_base_seq(net) == genid;
+ 	if (!genid_ok)
+ 		mutex_unlock(&nft_net->commit_mutex);
+ 
+@@ -12108,7 +12143,7 @@ static int __net_init nf_tables_init_net(struct net *net)
+ 	INIT_LIST_HEAD(&nft_net->module_list);
+ 	INIT_LIST_HEAD(&nft_net->notify_list);
+ 	mutex_init(&nft_net->commit_mutex);
+-	nft_net->base_seq = 1;
++	net->nft.base_seq = 1;
+ 	nft_net->gc_seq = 0;
+ 	nft_net->validate_state = NFT_VALIDATE_SKIP;
+ 	INIT_WORK(&nft_net->destroy_work, nf_tables_trans_destroy_work);
+diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
+index 88922e0e8e8377..e24493d9e77615 100644
+--- a/net/netfilter/nft_dynset.c
++++ b/net/netfilter/nft_dynset.c
+@@ -91,8 +91,9 @@ void nft_dynset_eval(const struct nft_expr *expr,
+ 		return;
+ 	}
+ 
+-	if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new,
+-			     expr, regs, &ext)) {
++	ext = set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new,
++			     expr, regs);
++	if (ext) {
+ 		if (priv->op == NFT_DYNSET_OP_UPDATE &&
+ 		    nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
+ 		    READ_ONCE(nft_set_ext_timeout(ext)->timeout) != 0) {
+diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
+index 63ef832b8aa710..58c5b14889c474 100644
+--- a/net/netfilter/nft_lookup.c
++++ b/net/netfilter/nft_lookup.c
+@@ -24,36 +24,73 @@ struct nft_lookup {
+ 	struct nft_set_binding		binding;
+ };
+ 
+-#ifdef CONFIG_MITIGATION_RETPOLINE
+-bool nft_set_do_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext)
++static const struct nft_set_ext *
++__nft_set_do_lookup(const struct net *net, const struct nft_set *set,
++		    const u32 *key)
+ {
++#ifdef CONFIG_MITIGATION_RETPOLINE
+ 	if (set->ops == &nft_set_hash_fast_type.ops)
+-		return nft_hash_lookup_fast(net, set, key, ext);
++		return nft_hash_lookup_fast(net, set, key);
+ 	if (set->ops == &nft_set_hash_type.ops)
+-		return nft_hash_lookup(net, set, key, ext);
++		return nft_hash_lookup(net, set, key);
+ 
+ 	if (set->ops == &nft_set_rhash_type.ops)
+-		return nft_rhash_lookup(net, set, key, ext);
++		return nft_rhash_lookup(net, set, key);
+ 
+ 	if (set->ops == &nft_set_bitmap_type.ops)
+-		return nft_bitmap_lookup(net, set, key, ext);
++		return nft_bitmap_lookup(net, set, key);
+ 
+ 	if (set->ops == &nft_set_pipapo_type.ops)
+-		return nft_pipapo_lookup(net, set, key, ext);
++		return nft_pipapo_lookup(net, set, key);
+ #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
+ 	if (set->ops == &nft_set_pipapo_avx2_type.ops)
+-		return nft_pipapo_avx2_lookup(net, set, key, ext);
++		return nft_pipapo_avx2_lookup(net, set, key);
+ #endif
+ 
+ 	if (set->ops == &nft_set_rbtree_type.ops)
+-		return nft_rbtree_lookup(net, set, key, ext);
++		return nft_rbtree_lookup(net, set, key);
+ 
+ 	WARN_ON_ONCE(1);
+-	return set->ops->lookup(net, set, key, ext);
++#endif
++	return set->ops->lookup(net, set, key);
++}
++
++static unsigned int nft_base_seq(const struct net *net)
++{
++	/* pairs with smp_store_release() in nf_tables_commit() */
++	return smp_load_acquire(&net->nft.base_seq);
++}
++
++static bool nft_lookup_should_retry(const struct net *net, unsigned int seq)
++{
++	return unlikely(seq != nft_base_seq(net));
++}
++
++const struct nft_set_ext *
++nft_set_do_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key)
++{
++	const struct nft_set_ext *ext;
++	unsigned int base_seq;
++
++	do {
++		base_seq = nft_base_seq(net);
++
++		ext = __nft_set_do_lookup(net, set, key);
++		if (ext)
++			break;
++		/* No match?  There is a small chance that lookup was
++		 * performed in the old generation, but nf_tables_commit()
++		 * already unlinked a (matching) element.
++		 *
++		 * We need to repeat the lookup to make sure that we didn't
++		 * miss a matching element in the new generation.
++		 */
++	} while (nft_lookup_should_retry(net, base_seq));
++
++	return ext;
+ }
+ EXPORT_SYMBOL_GPL(nft_set_do_lookup);
+-#endif
+ 
+ void nft_lookup_eval(const struct nft_expr *expr,
+ 		     struct nft_regs *regs,
+@@ -61,12 +98,12 @@ void nft_lookup_eval(const struct nft_expr *expr,
+ {
+ 	const struct nft_lookup *priv = nft_expr_priv(expr);
+ 	const struct nft_set *set = priv->set;
+-	const struct nft_set_ext *ext = NULL;
+ 	const struct net *net = nft_net(pkt);
++	const struct nft_set_ext *ext;
+ 	bool found;
+ 
+-	found =	nft_set_do_lookup(net, set, &regs->data[priv->sreg], &ext) ^
+-				  priv->invert;
++	ext = nft_set_do_lookup(net, set, &regs->data[priv->sreg]);
++	found = !!ext ^ priv->invert;
+ 	if (!found) {
+ 		ext = nft_set_catchall_lookup(net, set);
+ 		if (!ext) {
+diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
+index 09da7a3f9f9677..8ee66a86c3bc75 100644
+--- a/net/netfilter/nft_objref.c
++++ b/net/netfilter/nft_objref.c
+@@ -111,10 +111,9 @@ void nft_objref_map_eval(const struct nft_expr *expr,
+ 	struct net *net = nft_net(pkt);
+ 	const struct nft_set_ext *ext;
+ 	struct nft_object *obj;
+-	bool found;
+ 
+-	found = nft_set_do_lookup(net, set, &regs->data[priv->sreg], &ext);
+-	if (!found) {
++	ext = nft_set_do_lookup(net, set, &regs->data[priv->sreg]);
++	if (!ext) {
+ 		ext = nft_set_catchall_lookup(net, set);
+ 		if (!ext) {
+ 			regs->verdict.code = NFT_BREAK;
+diff --git a/net/netfilter/nft_set_bitmap.c b/net/netfilter/nft_set_bitmap.c
+index 12390d2e994fc6..8d3f040a904a2c 100644
+--- a/net/netfilter/nft_set_bitmap.c
++++ b/net/netfilter/nft_set_bitmap.c
+@@ -75,16 +75,21 @@ nft_bitmap_active(const u8 *bitmap, u32 idx, u32 off, u8 genmask)
+ }
+ 
+ INDIRECT_CALLABLE_SCOPE
+-bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext)
++const struct nft_set_ext *
++nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key)
+ {
+ 	const struct nft_bitmap *priv = nft_set_priv(set);
++	static const struct nft_set_ext found;
+ 	u8 genmask = nft_genmask_cur(net);
+ 	u32 idx, off;
+ 
+ 	nft_bitmap_location(set, key, &idx, &off);
+ 
+-	return nft_bitmap_active(priv->bitmap, idx, off, genmask);
++	if (nft_bitmap_active(priv->bitmap, idx, off, genmask))
++		return &found;
++
++	return NULL;
+ }
+ 
+ static struct nft_bitmap_elem *
+@@ -221,7 +226,8 @@ static void nft_bitmap_walk(const struct nft_ctx *ctx,
+ 	const struct nft_bitmap *priv = nft_set_priv(set);
+ 	struct nft_bitmap_elem *be;
+ 
+-	list_for_each_entry_rcu(be, &priv->list, head) {
++	list_for_each_entry_rcu(be, &priv->list, head,
++				lockdep_is_held(&nft_pernet(ctx->net)->commit_mutex)) {
+ 		if (iter->count < iter->skip)
+ 			goto cont;
+ 
+diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
+index abb0c8ec637191..9903c737c9f0ad 100644
+--- a/net/netfilter/nft_set_hash.c
++++ b/net/netfilter/nft_set_hash.c
+@@ -81,8 +81,9 @@ static const struct rhashtable_params nft_rhash_params = {
+ };
+ 
+ INDIRECT_CALLABLE_SCOPE
+-bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
+-		      const u32 *key, const struct nft_set_ext **ext)
++const struct nft_set_ext *
++nft_rhash_lookup(const struct net *net, const struct nft_set *set,
++		 const u32 *key)
+ {
+ 	struct nft_rhash *priv = nft_set_priv(set);
+ 	const struct nft_rhash_elem *he;
+@@ -95,9 +96,9 @@ bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
+ 
+ 	he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
+ 	if (he != NULL)
+-		*ext = &he->ext;
++		return &he->ext;
+ 
+-	return !!he;
++	return NULL;
+ }
+ 
+ static struct nft_elem_priv *
+@@ -120,14 +121,11 @@ nft_rhash_get(const struct net *net, const struct nft_set *set,
+ 	return ERR_PTR(-ENOENT);
+ }
+ 
+-static bool nft_rhash_update(struct nft_set *set, const u32 *key,
+-			     struct nft_elem_priv *
+-				   (*new)(struct nft_set *,
+-					  const struct nft_expr *,
+-					  struct nft_regs *regs),
+-			     const struct nft_expr *expr,
+-			     struct nft_regs *regs,
+-			     const struct nft_set_ext **ext)
++static const struct nft_set_ext *
++nft_rhash_update(struct nft_set *set, const u32 *key,
++		 struct nft_elem_priv *(*new)(struct nft_set *, const struct nft_expr *,
++		 struct nft_regs *regs),
++		 const struct nft_expr *expr, struct nft_regs *regs)
+ {
+ 	struct nft_rhash *priv = nft_set_priv(set);
+ 	struct nft_rhash_elem *he, *prev;
+@@ -161,14 +159,13 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
+ 	}
+ 
+ out:
+-	*ext = &he->ext;
+-	return true;
++	return &he->ext;
+ 
+ err2:
+ 	nft_set_elem_destroy(set, &he->priv, true);
+ 	atomic_dec(&set->nelems);
+ err1:
+-	return false;
++	return NULL;
+ }
+ 
+ static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
+@@ -507,8 +504,9 @@ struct nft_hash_elem {
+ };
+ 
+ INDIRECT_CALLABLE_SCOPE
+-bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
+-		     const u32 *key, const struct nft_set_ext **ext)
++const struct nft_set_ext *
++nft_hash_lookup(const struct net *net, const struct nft_set *set,
++		const u32 *key)
+ {
+ 	struct nft_hash *priv = nft_set_priv(set);
+ 	u8 genmask = nft_genmask_cur(net);
+@@ -519,12 +517,10 @@ bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
+ 	hash = reciprocal_scale(hash, priv->buckets);
+ 	hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
+ 		if (!memcmp(nft_set_ext_key(&he->ext), key, set->klen) &&
+-		    nft_set_elem_active(&he->ext, genmask)) {
+-			*ext = &he->ext;
+-			return true;
+-		}
++		    nft_set_elem_active(&he->ext, genmask))
++			return &he->ext;
+ 	}
+-	return false;
++	return NULL;
+ }
+ 
+ static struct nft_elem_priv *
+@@ -547,9 +543,9 @@ nft_hash_get(const struct net *net, const struct nft_set *set,
+ }
+ 
+ INDIRECT_CALLABLE_SCOPE
+-bool nft_hash_lookup_fast(const struct net *net,
+-			  const struct nft_set *set,
+-			  const u32 *key, const struct nft_set_ext **ext)
++const struct nft_set_ext *
++nft_hash_lookup_fast(const struct net *net, const struct nft_set *set,
++		     const u32 *key)
+ {
+ 	struct nft_hash *priv = nft_set_priv(set);
+ 	u8 genmask = nft_genmask_cur(net);
+@@ -562,12 +558,10 @@ bool nft_hash_lookup_fast(const struct net *net,
+ 	hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
+ 		k2 = *(u32 *)nft_set_ext_key(&he->ext)->data;
+ 		if (k1 == k2 &&
+-		    nft_set_elem_active(&he->ext, genmask)) {
+-			*ext = &he->ext;
+-			return true;
+-		}
++		    nft_set_elem_active(&he->ext, genmask))
++			return &he->ext;
+ 	}
+-	return false;
++	return NULL;
+ }
+ 
+ static u32 nft_jhash(const struct nft_set *set, const struct nft_hash *priv,
+diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
+index 9e4e25f2458f99..793790d79d1384 100644
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -397,37 +397,38 @@ int pipapo_refill(unsigned long *map, unsigned int len, unsigned int rules,
+ }
+ 
+ /**
+- * nft_pipapo_lookup() - Lookup function
+- * @net:	Network namespace
+- * @set:	nftables API set representation
+- * @key:	nftables API element representation containing key data
+- * @ext:	nftables API extension pointer, filled with matching reference
++ * pipapo_get() - Get matching element reference given key data
++ * @m:		storage containing the set elements
++ * @data:	Key data to be matched against existing elements
++ * @genmask:	If set, check that element is active in given genmask
++ * @tstamp:	timestamp to check for expired elements
+  *
+  * For more details, see DOC: Theory of Operation.
+  *
+- * Return: true on match, false otherwise.
++ * This is the main lookup function.  It matches key data against either
++ * the working match set or the uncommitted copy, depending on what the
++ * caller passed to us.
++ * nft_pipapo_get (lookup from userspace/control plane) and nft_pipapo_lookup
++ * (datapath lookup) pass the active copy.
++ * The insertion path will pass the uncommitted working copy.
++ *
++ * Return: pointer to &struct nft_pipapo_elem on match, NULL otherwise.
+  */
+-bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext)
++static struct nft_pipapo_elem *pipapo_get(const struct nft_pipapo_match *m,
++					  const u8 *data, u8 genmask,
++					  u64 tstamp)
+ {
+-	struct nft_pipapo *priv = nft_set_priv(set);
+ 	struct nft_pipapo_scratch *scratch;
+ 	unsigned long *res_map, *fill_map;
+-	u8 genmask = nft_genmask_cur(net);
+-	const struct nft_pipapo_match *m;
+ 	const struct nft_pipapo_field *f;
+-	const u8 *rp = (const u8 *)key;
+ 	bool map_index;
+ 	int i;
+ 
+ 	local_bh_disable();
+ 
+-	m = rcu_dereference(priv->match);
+-
+-	if (unlikely(!m || !*raw_cpu_ptr(m->scratch)))
+-		goto out;
+-
+ 	scratch = *raw_cpu_ptr(m->scratch);
++	if (unlikely(!scratch))
++		goto out;
+ 
+ 	map_index = scratch->map_index;
+ 
+@@ -444,12 +445,12 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
+ 		 * packet bytes value, then AND bucket value
+ 		 */
+ 		if (likely(f->bb == 8))
+-			pipapo_and_field_buckets_8bit(f, res_map, rp);
++			pipapo_and_field_buckets_8bit(f, res_map, data);
+ 		else
+-			pipapo_and_field_buckets_4bit(f, res_map, rp);
++			pipapo_and_field_buckets_4bit(f, res_map, data);
+ 		NFT_PIPAPO_GROUP_BITS_ARE_8_OR_4;
+ 
+-		rp += f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f);
++		data += f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f);
+ 
+ 		/* Now populate the bitmap for the next field, unless this is
+ 		 * the last field, in which case return the matched 'ext'
+@@ -465,13 +466,15 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
+ 			scratch->map_index = map_index;
+ 			local_bh_enable();
+ 
+-			return false;
++			return NULL;
+ 		}
+ 
+ 		if (last) {
+-			*ext = &f->mt[b].e->ext;
+-			if (unlikely(nft_set_elem_expired(*ext) ||
+-				     !nft_set_elem_active(*ext, genmask)))
++			struct nft_pipapo_elem *e;
++
++			e = f->mt[b].e;
++			if (unlikely(__nft_set_elem_expired(&e->ext, tstamp) ||
++				     !nft_set_elem_active(&e->ext, genmask)))
+ 				goto next_match;
+ 
+ 			/* Last field: we're just returning the key without
+@@ -481,8 +484,7 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
+ 			 */
+ 			scratch->map_index = map_index;
+ 			local_bh_enable();
+-
+-			return true;
++			return e;
+ 		}
+ 
+ 		/* Swap bitmap indices: res_map is the initial bitmap for the
+@@ -492,112 +494,54 @@ bool nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
+ 		map_index = !map_index;
+ 		swap(res_map, fill_map);
+ 
+-		rp += NFT_PIPAPO_GROUPS_PADDING(f);
++		data += NFT_PIPAPO_GROUPS_PADDING(f);
+ 	}
+ 
+ out:
+ 	local_bh_enable();
+-	return false;
++	return NULL;
+ }
+ 
+ /**
+- * pipapo_get() - Get matching element reference given key data
++ * nft_pipapo_lookup() - Dataplane fronted for main lookup function
+  * @net:	Network namespace
+  * @set:	nftables API set representation
+- * @m:		storage containing active/existing elements
+- * @data:	Key data to be matched against existing elements
+- * @genmask:	If set, check that element is active in given genmask
+- * @tstamp:	timestamp to check for expired elements
+- * @gfp:	the type of memory to allocate (see kmalloc).
++ * @key:	pointer to nft registers containing key data
++ *
++ * This function is called from the data path.  It will search for
++ * an element matching the given key in the current active copy.
++ * Unlike other set types, this uses NFT_GENMASK_ANY instead of
++ * nft_genmask_cur().
+  *
+- * This is essentially the same as the lookup function, except that it matches
+- * key data against the uncommitted copy and doesn't use preallocated maps for
+- * bitmap results.
++ * This is because new (future) elements are not reachable from
++ * priv->match, they get added to priv->clone instead.
++ * When the commit phase flips the generation bitmask, the
++ * 'now old' entries are skipped but without the 'now current'
++ * elements becoming visible. Using nft_genmask_cur() thus creates
++ * inconsistent state: matching old entries get skipped but thew
++ * newly matching entries are unreachable.
+  *
+- * Return: pointer to &struct nft_pipapo_elem on match, error pointer otherwise.
++ * GENMASK will still find the 'now old' entries which ensures consistent
++ * priv->match view.
++ *
++ * nft_pipapo_commit swaps ->clone and ->match shortly after the
++ * genbit flip.  As ->clone doesn't contain the old entries in the first
++ * place, lookup will only find the now-current ones.
++ *
++ * Return: ntables API extension pointer or NULL if no match.
+  */
+-static struct nft_pipapo_elem *pipapo_get(const struct net *net,
+-					  const struct nft_set *set,
+-					  const struct nft_pipapo_match *m,
+-					  const u8 *data, u8 genmask,
+-					  u64 tstamp, gfp_t gfp)
++const struct nft_set_ext *
++nft_pipapo_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key)
+ {
+-	struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT);
+-	unsigned long *res_map, *fill_map = NULL;
+-	const struct nft_pipapo_field *f;
+-	int i;
+-
+-	if (m->bsize_max == 0)
+-		return ret;
+-
+-	res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), gfp);
+-	if (!res_map) {
+-		ret = ERR_PTR(-ENOMEM);
+-		goto out;
+-	}
+-
+-	fill_map = kcalloc(m->bsize_max, sizeof(*res_map), gfp);
+-	if (!fill_map) {
+-		ret = ERR_PTR(-ENOMEM);
+-		goto out;
+-	}
+-
+-	pipapo_resmap_init(m, res_map);
+-
+-	nft_pipapo_for_each_field(f, i, m) {
+-		bool last = i == m->field_count - 1;
+-		int b;
+-
+-		/* For each bit group: select lookup table bucket depending on
+-		 * packet bytes value, then AND bucket value
+-		 */
+-		if (f->bb == 8)
+-			pipapo_and_field_buckets_8bit(f, res_map, data);
+-		else if (f->bb == 4)
+-			pipapo_and_field_buckets_4bit(f, res_map, data);
+-		else
+-			BUG();
+-
+-		data += f->groups / NFT_PIPAPO_GROUPS_PER_BYTE(f);
+-
+-		/* Now populate the bitmap for the next field, unless this is
+-		 * the last field, in which case return the matched 'ext'
+-		 * pointer if any.
+-		 *
+-		 * Now res_map contains the matching bitmap, and fill_map is the
+-		 * bitmap for the next field.
+-		 */
+-next_match:
+-		b = pipapo_refill(res_map, f->bsize, f->rules, fill_map, f->mt,
+-				  last);
+-		if (b < 0)
+-			goto out;
+-
+-		if (last) {
+-			if (__nft_set_elem_expired(&f->mt[b].e->ext, tstamp))
+-				goto next_match;
+-			if ((genmask &&
+-			     !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
+-				goto next_match;
+-
+-			ret = f->mt[b].e;
+-			goto out;
+-		}
+-
+-		data += NFT_PIPAPO_GROUPS_PADDING(f);
++	struct nft_pipapo *priv = nft_set_priv(set);
++	const struct nft_pipapo_match *m;
++	const struct nft_pipapo_elem *e;
+ 
+-		/* Swap bitmap indices: fill_map will be the initial bitmap for
+-		 * the next field (i.e. the new res_map), and res_map is
+-		 * guaranteed to be all-zeroes at this point, ready to be filled
+-		 * according to the next mapping table.
+-		 */
+-		swap(res_map, fill_map);
+-	}
++	m = rcu_dereference(priv->match);
++	e = pipapo_get(m, (const u8 *)key, NFT_GENMASK_ANY, get_jiffies_64());
+ 
+-out:
+-	kfree(fill_map);
+-	kfree(res_map);
+-	return ret;
++	return e ? &e->ext : NULL;
+ }
+ 
+ /**
+@@ -606,6 +550,11 @@ static struct nft_pipapo_elem *pipapo_get(const struct net *net,
+  * @set:	nftables API set representation
+  * @elem:	nftables API element representation containing key data
+  * @flags:	Unused
++ *
++ * This function is called from the control plane path under
++ * RCU read lock.
++ *
++ * Return: set element private pointer or ERR_PTR(-ENOENT).
+  */
+ static struct nft_elem_priv *
+ nft_pipapo_get(const struct net *net, const struct nft_set *set,
+@@ -615,11 +564,10 @@ nft_pipapo_get(const struct net *net, const struct nft_set *set,
+ 	struct nft_pipapo_match *m = rcu_dereference(priv->match);
+ 	struct nft_pipapo_elem *e;
+ 
+-	e = pipapo_get(net, set, m, (const u8 *)elem->key.val.data,
+-		       nft_genmask_cur(net), get_jiffies_64(),
+-		       GFP_ATOMIC);
+-	if (IS_ERR(e))
+-		return ERR_CAST(e);
++	e = pipapo_get(m, (const u8 *)elem->key.val.data,
++		       nft_genmask_cur(net), get_jiffies_64());
++	if (!e)
++		return ERR_PTR(-ENOENT);
+ 
+ 	return &e->priv;
+ }
+@@ -1344,8 +1292,8 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
+ 	else
+ 		end = start;
+ 
+-	dup = pipapo_get(net, set, m, start, genmask, tstamp, GFP_KERNEL);
+-	if (!IS_ERR(dup)) {
++	dup = pipapo_get(m, start, genmask, tstamp);
++	if (dup) {
+ 		/* Check if we already have the same exact entry */
+ 		const struct nft_data *dup_key, *dup_end;
+ 
+@@ -1364,15 +1312,9 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
+ 		return -ENOTEMPTY;
+ 	}
+ 
+-	if (PTR_ERR(dup) == -ENOENT) {
+-		/* Look for partially overlapping entries */
+-		dup = pipapo_get(net, set, m, end, nft_genmask_next(net), tstamp,
+-				 GFP_KERNEL);
+-	}
+-
+-	if (PTR_ERR(dup) != -ENOENT) {
+-		if (IS_ERR(dup))
+-			return PTR_ERR(dup);
++	/* Look for partially overlapping entries */
++	dup = pipapo_get(m, end, nft_genmask_next(net), tstamp);
++	if (dup) {
+ 		*elem_priv = &dup->priv;
+ 		return -ENOTEMPTY;
+ 	}
+@@ -1913,9 +1855,9 @@ nft_pipapo_deactivate(const struct net *net, const struct nft_set *set,
+ 	if (!m)
+ 		return NULL;
+ 
+-	e = pipapo_get(net, set, m, (const u8 *)elem->key.val.data,
+-		       nft_genmask_next(net), nft_net_tstamp(net), GFP_KERNEL);
+-	if (IS_ERR(e))
++	e = pipapo_get(m, (const u8 *)elem->key.val.data,
++		       nft_genmask_next(net), nft_net_tstamp(net));
++	if (!e)
+ 		return NULL;
+ 
+ 	nft_set_elem_change_active(net, set, &e->ext);
+diff --git a/net/netfilter/nft_set_pipapo_avx2.c b/net/netfilter/nft_set_pipapo_avx2.c
+index be7c16c79f711e..39e356c9687a98 100644
+--- a/net/netfilter/nft_set_pipapo_avx2.c
++++ b/net/netfilter/nft_set_pipapo_avx2.c
+@@ -1146,26 +1146,27 @@ static inline void pipapo_resmap_init_avx2(const struct nft_pipapo_match *m, uns
+  *
+  * Return: true on match, false otherwise.
+  */
+-bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
+-			    const u32 *key, const struct nft_set_ext **ext)
++const struct nft_set_ext *
++nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
++		       const u32 *key)
+ {
+ 	struct nft_pipapo *priv = nft_set_priv(set);
++	const struct nft_set_ext *ext = NULL;
+ 	struct nft_pipapo_scratch *scratch;
+-	u8 genmask = nft_genmask_cur(net);
+ 	const struct nft_pipapo_match *m;
+ 	const struct nft_pipapo_field *f;
+ 	const u8 *rp = (const u8 *)key;
+ 	unsigned long *res, *fill;
+ 	bool map_index;
+-	int i, ret = 0;
++	int i;
+ 
+ 	local_bh_disable();
+ 
+ 	if (unlikely(!irq_fpu_usable())) {
+-		bool fallback_res = nft_pipapo_lookup(net, set, key, ext);
++		ext = nft_pipapo_lookup(net, set, key);
+ 
+ 		local_bh_enable();
+-		return fallback_res;
++		return ext;
+ 	}
+ 
+ 	m = rcu_dereference(priv->match);
+@@ -1182,7 +1183,7 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
+ 	if (unlikely(!scratch)) {
+ 		kernel_fpu_end();
+ 		local_bh_enable();
+-		return false;
++		return NULL;
+ 	}
+ 
+ 	map_index = scratch->map_index;
+@@ -1197,6 +1198,7 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
+ next_match:
+ 	nft_pipapo_for_each_field(f, i, m) {
+ 		bool last = i == m->field_count - 1, first = !i;
++		int ret = 0;
+ 
+ #define NFT_SET_PIPAPO_AVX2_LOOKUP(b, n)				\
+ 		(ret = nft_pipapo_avx2_lookup_##b##b_##n(res, fill, f,	\
+@@ -1244,13 +1246,12 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
+ 			goto out;
+ 
+ 		if (last) {
+-			*ext = &f->mt[ret].e->ext;
+-			if (unlikely(nft_set_elem_expired(*ext) ||
+-				     !nft_set_elem_active(*ext, genmask))) {
+-				ret = 0;
++			const struct nft_set_ext *e = &f->mt[ret].e->ext;
++
++			if (unlikely(nft_set_elem_expired(e)))
+ 				goto next_match;
+-			}
+ 
++			ext = e;
+ 			goto out;
+ 		}
+ 
+@@ -1264,5 +1265,5 @@ bool nft_pipapo_avx2_lookup(const struct net *net, const struct nft_set *set,
+ 	kernel_fpu_end();
+ 	local_bh_enable();
+ 
+-	return ret >= 0;
++	return ext;
+ }
+diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
+index 2e8ef16ff191d4..b1f04168ec9377 100644
+--- a/net/netfilter/nft_set_rbtree.c
++++ b/net/netfilter/nft_set_rbtree.c
+@@ -52,9 +52,9 @@ static bool nft_rbtree_elem_expired(const struct nft_rbtree_elem *rbe)
+ 	return nft_set_elem_expired(&rbe->ext);
+ }
+ 
+-static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
+-				const u32 *key, const struct nft_set_ext **ext,
+-				unsigned int seq)
++static const struct nft_set_ext *
++__nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
++		    const u32 *key, unsigned int seq)
+ {
+ 	struct nft_rbtree *priv = nft_set_priv(set);
+ 	const struct nft_rbtree_elem *rbe, *interval = NULL;
+@@ -65,7 +65,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
+ 	parent = rcu_dereference_raw(priv->root.rb_node);
+ 	while (parent != NULL) {
+ 		if (read_seqcount_retry(&priv->count, seq))
+-			return false;
++			return NULL;
+ 
+ 		rbe = rb_entry(parent, struct nft_rbtree_elem, node);
+ 
+@@ -77,7 +77,9 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
+ 			    nft_rbtree_interval_end(rbe) &&
+ 			    nft_rbtree_interval_start(interval))
+ 				continue;
+-			interval = rbe;
++			if (nft_set_elem_active(&rbe->ext, genmask) &&
++			    !nft_rbtree_elem_expired(rbe))
++				interval = rbe;
+ 		} else if (d > 0)
+ 			parent = rcu_dereference_raw(parent->rb_right);
+ 		else {
+@@ -87,50 +89,46 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
+ 			}
+ 
+ 			if (nft_rbtree_elem_expired(rbe))
+-				return false;
++				return NULL;
+ 
+ 			if (nft_rbtree_interval_end(rbe)) {
+ 				if (nft_set_is_anonymous(set))
+-					return false;
++					return NULL;
+ 				parent = rcu_dereference_raw(parent->rb_left);
+ 				interval = NULL;
+ 				continue;
+ 			}
+ 
+-			*ext = &rbe->ext;
+-			return true;
++			return &rbe->ext;
+ 		}
+ 	}
+ 
+ 	if (set->flags & NFT_SET_INTERVAL && interval != NULL &&
+-	    nft_set_elem_active(&interval->ext, genmask) &&
+-	    !nft_rbtree_elem_expired(interval) &&
+-	    nft_rbtree_interval_start(interval)) {
+-		*ext = &interval->ext;
+-		return true;
+-	}
++	    nft_rbtree_interval_start(interval))
++		return &interval->ext;
+ 
+-	return false;
++	return NULL;
+ }
+ 
+ INDIRECT_CALLABLE_SCOPE
+-bool nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
+-		       const u32 *key, const struct nft_set_ext **ext)
++const struct nft_set_ext *
++nft_rbtree_lookup(const struct net *net, const struct nft_set *set,
++		  const u32 *key)
+ {
+ 	struct nft_rbtree *priv = nft_set_priv(set);
+ 	unsigned int seq = read_seqcount_begin(&priv->count);
+-	bool ret;
++	const struct nft_set_ext *ext;
+ 
+-	ret = __nft_rbtree_lookup(net, set, key, ext, seq);
+-	if (ret || !read_seqcount_retry(&priv->count, seq))
+-		return ret;
++	ext = __nft_rbtree_lookup(net, set, key, seq);
++	if (ext || !read_seqcount_retry(&priv->count, seq))
++		return ext;
+ 
+ 	read_lock_bh(&priv->lock);
+ 	seq = read_seqcount_begin(&priv->count);
+-	ret = __nft_rbtree_lookup(net, set, key, ext, seq);
++	ext = __nft_rbtree_lookup(net, set, key, seq);
+ 	read_unlock_bh(&priv->lock);
+ 
+-	return ret;
++	return ext;
+ }
+ 
+ static bool __nft_rbtree_get(const struct net *net, const struct nft_set *set,
+diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
+index 104732d3454348..978c129c609501 100644
+--- a/net/netlink/genetlink.c
++++ b/net/netlink/genetlink.c
+@@ -1836,6 +1836,9 @@ static int genl_bind(struct net *net, int group)
+ 		    !ns_capable(net->user_ns, CAP_SYS_ADMIN))
+ 			ret = -EPERM;
+ 
++		if (ret)
++			break;
++
+ 		if (family->bind)
+ 			family->bind(i);
+ 
+diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
+index 73bc39281ef5f5..9b45fbdc90cabe 100644
+--- a/net/sunrpc/sched.c
++++ b/net/sunrpc/sched.c
+@@ -276,8 +276,6 @@ EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
+ 
+ static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
+ {
+-	if (unlikely(current->flags & PF_EXITING))
+-		return -EINTR;
+ 	schedule();
+ 	if (signal_pending_state(mode, current))
+ 		return -ERESTARTSYS;
+diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
+index c5f7bbf5775ff8..3aa987e7f0724d 100644
+--- a/net/sunrpc/xprtsock.c
++++ b/net/sunrpc/xprtsock.c
+@@ -407,9 +407,9 @@ xs_sock_recv_cmsg(struct socket *sock, unsigned int *msg_flags, int flags)
+ 	iov_iter_kvec(&msg.msg_iter, ITER_DEST, &alert_kvec, 1,
+ 		      alert_kvec.iov_len);
+ 	ret = sock_recvmsg(sock, &msg, flags);
+-	if (ret > 0 &&
+-	    tls_get_record_type(sock->sk, &u.cmsg) == TLS_RECORD_TYPE_ALERT) {
+-		iov_iter_revert(&msg.msg_iter, ret);
++	if (ret > 0) {
++		if (tls_get_record_type(sock->sk, &u.cmsg) == TLS_RECORD_TYPE_ALERT)
++			iov_iter_revert(&msg.msg_iter, ret);
+ 		ret = xs_sock_process_cmsg(sock, &msg, msg_flags, &u.cmsg,
+ 					   -EAGAIN);
+ 	}
+diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
+index 72c000c0ae5f57..de331541fdb387 100644
+--- a/net/xdp/xsk.c
++++ b/net/xdp/xsk.c
+@@ -36,6 +36,20 @@
+ #define TX_BATCH_SIZE 32
+ #define MAX_PER_SOCKET_BUDGET (TX_BATCH_SIZE)
+ 
++struct xsk_addr_node {
++	u64 addr;
++	struct list_head addr_node;
++};
++
++struct xsk_addr_head {
++	u32 num_descs;
++	struct list_head addrs_list;
++};
++
++static struct kmem_cache *xsk_tx_generic_cache;
++
++#define XSKCB(skb) ((struct xsk_addr_head *)((skb)->cb))
++
+ void xsk_set_rx_need_wakeup(struct xsk_buff_pool *pool)
+ {
+ 	if (pool->cached_need_wakeup & XDP_WAKEUP_RX)
+@@ -528,24 +542,43 @@ static int xsk_wakeup(struct xdp_sock *xs, u8 flags)
+ 	return dev->netdev_ops->ndo_xsk_wakeup(dev, xs->queue_id, flags);
+ }
+ 
+-static int xsk_cq_reserve_addr_locked(struct xsk_buff_pool *pool, u64 addr)
++static int xsk_cq_reserve_locked(struct xsk_buff_pool *pool)
+ {
+ 	unsigned long flags;
+ 	int ret;
+ 
+ 	spin_lock_irqsave(&pool->cq_lock, flags);
+-	ret = xskq_prod_reserve_addr(pool->cq, addr);
++	ret = xskq_prod_reserve(pool->cq);
+ 	spin_unlock_irqrestore(&pool->cq_lock, flags);
+ 
+ 	return ret;
+ }
+ 
+-static void xsk_cq_submit_locked(struct xsk_buff_pool *pool, u32 n)
++static void xsk_cq_submit_addr_locked(struct xsk_buff_pool *pool,
++				      struct sk_buff *skb)
+ {
++	struct xsk_addr_node *pos, *tmp;
++	u32 descs_processed = 0;
+ 	unsigned long flags;
++	u32 idx;
+ 
+ 	spin_lock_irqsave(&pool->cq_lock, flags);
+-	xskq_prod_submit_n(pool->cq, n);
++	idx = xskq_get_prod(pool->cq);
++
++	xskq_prod_write_addr(pool->cq, idx,
++			     (u64)(uintptr_t)skb_shinfo(skb)->destructor_arg);
++	descs_processed++;
++
++	if (unlikely(XSKCB(skb)->num_descs > 1)) {
++		list_for_each_entry_safe(pos, tmp, &XSKCB(skb)->addrs_list, addr_node) {
++			xskq_prod_write_addr(pool->cq, idx + descs_processed,
++					     pos->addr);
++			descs_processed++;
++			list_del(&pos->addr_node);
++			kmem_cache_free(xsk_tx_generic_cache, pos);
++		}
++	}
++	xskq_prod_submit_n(pool->cq, descs_processed);
+ 	spin_unlock_irqrestore(&pool->cq_lock, flags);
+ }
+ 
+@@ -558,9 +591,14 @@ static void xsk_cq_cancel_locked(struct xsk_buff_pool *pool, u32 n)
+ 	spin_unlock_irqrestore(&pool->cq_lock, flags);
+ }
+ 
++static void xsk_inc_num_desc(struct sk_buff *skb)
++{
++	XSKCB(skb)->num_descs++;
++}
++
+ static u32 xsk_get_num_desc(struct sk_buff *skb)
+ {
+-	return skb ? (long)skb_shinfo(skb)->destructor_arg : 0;
++	return XSKCB(skb)->num_descs;
+ }
+ 
+ static void xsk_destruct_skb(struct sk_buff *skb)
+@@ -572,23 +610,33 @@ static void xsk_destruct_skb(struct sk_buff *skb)
+ 		*compl->tx_timestamp = ktime_get_tai_fast_ns();
+ 	}
+ 
+-	xsk_cq_submit_locked(xdp_sk(skb->sk)->pool, xsk_get_num_desc(skb));
++	xsk_cq_submit_addr_locked(xdp_sk(skb->sk)->pool, skb);
+ 	sock_wfree(skb);
+ }
+ 
+-static void xsk_set_destructor_arg(struct sk_buff *skb)
++static void xsk_set_destructor_arg(struct sk_buff *skb, u64 addr)
+ {
+-	long num = xsk_get_num_desc(xdp_sk(skb->sk)->skb) + 1;
+-
+-	skb_shinfo(skb)->destructor_arg = (void *)num;
++	BUILD_BUG_ON(sizeof(struct xsk_addr_head) > sizeof(skb->cb));
++	INIT_LIST_HEAD(&XSKCB(skb)->addrs_list);
++	XSKCB(skb)->num_descs = 0;
++	skb_shinfo(skb)->destructor_arg = (void *)(uintptr_t)addr;
+ }
+ 
+ static void xsk_consume_skb(struct sk_buff *skb)
+ {
+ 	struct xdp_sock *xs = xdp_sk(skb->sk);
++	u32 num_descs = xsk_get_num_desc(skb);
++	struct xsk_addr_node *pos, *tmp;
++
++	if (unlikely(num_descs > 1)) {
++		list_for_each_entry_safe(pos, tmp, &XSKCB(skb)->addrs_list, addr_node) {
++			list_del(&pos->addr_node);
++			kmem_cache_free(xsk_tx_generic_cache, pos);
++		}
++	}
+ 
+ 	skb->destructor = sock_wfree;
+-	xsk_cq_cancel_locked(xs->pool, xsk_get_num_desc(skb));
++	xsk_cq_cancel_locked(xs->pool, num_descs);
+ 	/* Free skb without triggering the perf drop trace */
+ 	consume_skb(skb);
+ 	xs->skb = NULL;
+@@ -605,6 +653,7 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,
+ {
+ 	struct xsk_buff_pool *pool = xs->pool;
+ 	u32 hr, len, ts, offset, copy, copied;
++	struct xsk_addr_node *xsk_addr;
+ 	struct sk_buff *skb = xs->skb;
+ 	struct page *page;
+ 	void *buffer;
+@@ -619,6 +668,19 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,
+ 			return ERR_PTR(err);
+ 
+ 		skb_reserve(skb, hr);
++
++		xsk_set_destructor_arg(skb, desc->addr);
++	} else {
++		xsk_addr = kmem_cache_zalloc(xsk_tx_generic_cache, GFP_KERNEL);
++		if (!xsk_addr)
++			return ERR_PTR(-ENOMEM);
++
++		/* in case of -EOVERFLOW that could happen below,
++		 * xsk_consume_skb() will release this node as whole skb
++		 * would be dropped, which implies freeing all list elements
++		 */
++		xsk_addr->addr = desc->addr;
++		list_add_tail(&xsk_addr->addr_node, &XSKCB(skb)->addrs_list);
+ 	}
+ 
+ 	addr = desc->addr;
+@@ -690,8 +752,11 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
+ 			err = skb_store_bits(skb, 0, buffer, len);
+ 			if (unlikely(err))
+ 				goto free_err;
++
++			xsk_set_destructor_arg(skb, desc->addr);
+ 		} else {
+ 			int nr_frags = skb_shinfo(skb)->nr_frags;
++			struct xsk_addr_node *xsk_addr;
+ 			struct page *page;
+ 			u8 *vaddr;
+ 
+@@ -706,12 +771,22 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
+ 				goto free_err;
+ 			}
+ 
++			xsk_addr = kmem_cache_zalloc(xsk_tx_generic_cache, GFP_KERNEL);
++			if (!xsk_addr) {
++				__free_page(page);
++				err = -ENOMEM;
++				goto free_err;
++			}
++
+ 			vaddr = kmap_local_page(page);
+ 			memcpy(vaddr, buffer, len);
+ 			kunmap_local(vaddr);
+ 
+ 			skb_add_rx_frag(skb, nr_frags, page, 0, len, PAGE_SIZE);
+ 			refcount_add(PAGE_SIZE, &xs->sk.sk_wmem_alloc);
++
++			xsk_addr->addr = desc->addr;
++			list_add_tail(&xsk_addr->addr_node, &XSKCB(skb)->addrs_list);
+ 		}
+ 
+ 		if (first_frag && desc->options & XDP_TX_METADATA) {
+@@ -755,7 +830,7 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
+ 	skb->mark = READ_ONCE(xs->sk.sk_mark);
+ 	skb->destructor = xsk_destruct_skb;
+ 	xsk_tx_metadata_to_compl(meta, &skb_shinfo(skb)->xsk_meta);
+-	xsk_set_destructor_arg(skb);
++	xsk_inc_num_desc(skb);
+ 
+ 	return skb;
+ 
+@@ -765,7 +840,7 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
+ 
+ 	if (err == -EOVERFLOW) {
+ 		/* Drop the packet */
+-		xsk_set_destructor_arg(xs->skb);
++		xsk_inc_num_desc(xs->skb);
+ 		xsk_drop_skb(xs->skb);
+ 		xskq_cons_release(xs->tx);
+ 	} else {
+@@ -807,7 +882,7 @@ static int __xsk_generic_xmit(struct sock *sk)
+ 		 * if there is space in it. This avoids having to implement
+ 		 * any buffering in the Tx path.
+ 		 */
+-		err = xsk_cq_reserve_addr_locked(xs->pool, desc.addr);
++		err = xsk_cq_reserve_locked(xs->pool);
+ 		if (err) {
+ 			err = -EAGAIN;
+ 			goto out;
+@@ -1795,8 +1870,18 @@ static int __init xsk_init(void)
+ 	if (err)
+ 		goto out_pernet;
+ 
++	xsk_tx_generic_cache = kmem_cache_create("xsk_generic_xmit_cache",
++						 sizeof(struct xsk_addr_node),
++						 0, SLAB_HWCACHE_ALIGN, NULL);
++	if (!xsk_tx_generic_cache) {
++		err = -ENOMEM;
++		goto out_unreg_notif;
++	}
++
+ 	return 0;
+ 
++out_unreg_notif:
++	unregister_netdevice_notifier(&xsk_netdev_notifier);
+ out_pernet:
+ 	unregister_pernet_subsys(&xsk_net_ops);
+ out_sk:
+diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h
+index 46d87e961ad6d3..f16f390370dc43 100644
+--- a/net/xdp/xsk_queue.h
++++ b/net/xdp/xsk_queue.h
+@@ -344,6 +344,11 @@ static inline u32 xskq_cons_present_entries(struct xsk_queue *q)
+ 
+ /* Functions for producers */
+ 
++static inline u32 xskq_get_prod(struct xsk_queue *q)
++{
++	return READ_ONCE(q->ring->producer);
++}
++
+ static inline u32 xskq_prod_nb_free(struct xsk_queue *q, u32 max)
+ {
+ 	u32 free_entries = q->nentries - (q->cached_prod - q->cached_cons);
+@@ -390,6 +395,13 @@ static inline int xskq_prod_reserve_addr(struct xsk_queue *q, u64 addr)
+ 	return 0;
+ }
+ 
++static inline void xskq_prod_write_addr(struct xsk_queue *q, u32 idx, u64 addr)
++{
++	struct xdp_umem_ring *ring = (struct xdp_umem_ring *)q->ring;
++
++	ring->desc[idx & q->ring_mask] = addr;
++}
++
+ static inline void xskq_prod_write_addr_batch(struct xsk_queue *q, struct xdp_desc *descs,
+ 					      u32 nb_entries)
+ {
+diff --git a/samples/ftrace/ftrace-direct-modify.c b/samples/ftrace/ftrace-direct-modify.c
+index cfea7a38befb05..da3a9f2091f55b 100644
+--- a/samples/ftrace/ftrace-direct-modify.c
++++ b/samples/ftrace/ftrace-direct-modify.c
+@@ -75,8 +75,8 @@ asm (
+ 	CALL_DEPTH_ACCOUNT
+ "	call my_direct_func1\n"
+ "	leave\n"
+-"	.size		my_tramp1, .-my_tramp1\n"
+ 	ASM_RET
++"	.size		my_tramp1, .-my_tramp1\n"
+ 
+ "	.type		my_tramp2, @function\n"
+ "	.globl		my_tramp2\n"
+diff --git a/tools/testing/selftests/net/can/config b/tools/testing/selftests/net/can/config
+new file mode 100644
+index 00000000000000..188f7979667097
+--- /dev/null
++++ b/tools/testing/selftests/net/can/config
+@@ -0,0 +1,3 @@
++CONFIG_CAN=m
++CONFIG_CAN_DEV=m
++CONFIG_CAN_VCAN=m

diff --git a/2991_libbpf_add_WERROR_option.patch b/2991_libbpf_add_WERROR_option.patch
index e8649909..39d485f9 100644
--- a/2991_libbpf_add_WERROR_option.patch
+++ b/2991_libbpf_add_WERROR_option.patch
@@ -1,17 +1,6 @@
 Subject: [PATCH] tools/libbpf: add WERROR option
-Date: Sat,  5 Jul 2025 11:43:12 +0100
-Message-ID: <7e6c41e47c6a8ab73945e6aac319e0dd53337e1b.1751712192.git.sam@gentoo.org>
-X-Mailer: git-send-email 2.50.0
-Precedence: bulk
-X-Mailing-List: bpf@vger.kernel.org
-List-Id: <bpf.vger.kernel.org>
-List-Subscribe: <mailto:bpf+subscribe@vger.kernel.org>
-List-Unsubscribe: <mailto:bpf+unsubscribe@vger.kernel.org>
-MIME-Version: 1.0
-Content-Transfer-Encoding: 8bit
 
 Check the 'WERROR' variable and suppress adding '-Werror' if WERROR=0.
-
 This mirrors what tools/perf and other directories in tools do to handle
 -Werror rather than adding it unconditionally.
 


             reply	other threads:[~2025-09-20  5:25 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-20  5:25 Arisu Tachibana [this message]
  -- strict thread matches above, loose matches on Subject: below --
2025-10-13 11:56 [gentoo-commits] proj/linux-patches:6.16 commit in: / Arisu Tachibana
2025-10-06 12:01 Arisu Tachibana
2025-10-06 11:06 Arisu Tachibana
2025-10-02 14:17 Arisu Tachibana
2025-10-02 14:14 Arisu Tachibana
2025-10-02 13:42 Arisu Tachibana
2025-10-02 13:30 Arisu Tachibana
2025-10-02 13:25 Arisu Tachibana
2025-10-02  3:28 Arisu Tachibana
2025-10-02  3:28 Arisu Tachibana
2025-10-02  3:12 Arisu Tachibana
2025-09-25 12:02 Arisu Tachibana
2025-09-20  6:29 Arisu Tachibana
2025-09-20  6:29 Arisu Tachibana
2025-09-20  5:31 Arisu Tachibana
2025-09-12  3:56 Arisu Tachibana
2025-09-10  6:18 Arisu Tachibana
2025-09-10  5:57 Arisu Tachibana
2025-09-10  5:30 Arisu Tachibana
2025-09-05 14:01 Arisu Tachibana
2025-09-04 15:46 Arisu Tachibana
2025-09-04 15:33 Arisu Tachibana
2025-08-28 16:37 Arisu Tachibana
2025-08-28 16:01 Arisu Tachibana
2025-08-28 15:31 Arisu Tachibana
2025-08-28 15:19 Arisu Tachibana
2025-08-28 15:14 Arisu Tachibana
2025-08-28 15:14 Arisu Tachibana
2025-08-25  0:00 Arisu Tachibana
2025-08-24 23:09 Arisu Tachibana
2025-08-21  4:31 Arisu Tachibana
2025-08-21  4:31 Arisu Tachibana
2025-08-21  1:07 Arisu Tachibana
2025-08-21  1:00 Arisu Tachibana
2025-08-21  0:27 Arisu Tachibana
2025-08-16  5:54 Arisu Tachibana
2025-08-16  5:54 Arisu Tachibana
2025-08-16  5:21 Arisu Tachibana
2025-08-16  4:02 Arisu Tachibana
2025-08-16  3:07 Arisu Tachibana
2025-07-29  7:43 Arisu Tachibana

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1758345920.9ffd46d3a792ef5eb448d3a3fcf684e769b965d5.alicef@gentoo \
    --to=alicef@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox