aboutsummaryrefslogtreecommitdiffstats
diff options
-rw-r--r--queue-6.12/alsa-hda-realtek-bass-speaker-fixup-for-asus-um5606k.patch43
-rw-r--r--queue-6.12/arm64-dts-rockchip-add-avdd-hdmi-supplies-to-rockpro.patch74
-rw-r--r--queue-6.12/btrfs-do-proper-folio-cleanup-when-cow_file_range-fa.patch286
-rw-r--r--queue-6.12/btrfs-do-regular-iput-instead-of-delayed-iput-during.patch47
-rw-r--r--queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch54
-rw-r--r--queue-6.12/btrfs-make-the-extent-map-shrinker-run-asynchronousl.patch243
-rw-r--r--queue-6.12/btrfs-skip-inodes-without-loaded-extent-maps-when-sh.patch161
-rw-r--r--queue-6.12/btrfs-zoned-fix-extent-range-end-unlock-in-cow_file_.patch135
-rw-r--r--queue-6.12/drm-amdkfd-fix-instruction-hazard-in-gfx12-trap-hand.patch932
-rw-r--r--queue-6.12/drm-amdkfd-remove-gfx-12-trap-handler-page-size-cap.patch37
-rw-r--r--queue-6.12/drm-fbdev-dma-add-shadow-buffering-for-deferred-i-o.patch347
-rw-r--r--queue-6.12/drm-msm-dp-account-for-widebus-and-yuv420-during-mod.patch75
-rw-r--r--queue-6.12/drm-xe-carve-out-wopcm-portion-from-the-stolen-memor.patch120
-rw-r--r--queue-6.12/iio-dac-ad3552r-changes-to-use-field_prep.patch310
-rw-r--r--queue-6.12/iio-dac-ad3552r-common-fix-ad3541-2r-ranges.patch95
-rw-r--r--queue-6.12/iio-dac-ad3552r-extract-common-code-no-changes-in-be.patch1002
-rw-r--r--queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch336
-rw-r--r--queue-6.12/loongarch-set-hugetlb-mmap-base-address-aligned-with.patch88
-rw-r--r--queue-6.12/net-stmmac-fix-accessing-freed-irq-affinity_hint.patch63
-rw-r--r--queue-6.12/riscv-atomic-do-proper-sign-extension-also-for-unsig.patch46
-rw-r--r--queue-6.12/series26
-rw-r--r--queue-6.12/spi-fsl-qspi-fix-double-cleanup-in-probe-error-path.patch61
-rw-r--r--queue-6.12/spi-fsl-qspi-support-per-spi-mem-operation-frequency.patch76
-rw-r--r--queue-6.12/spi-fsl-qspi-use-devm-function-instead-of-driver-rem.patch96
-rw-r--r--queue-6.12/spi-spi-mem-add-a-new-controller-capability.patch71
-rw-r--r--queue-6.12/spi-spi-mem-extend-spi-mem-operations-with-a-per-ope.patch220
-rw-r--r--queue-6.12/usb-typec-tcpm-pssourceofftimer-timeout-in-pr_swap-e.patch54
27 files changed, 5098 insertions, 0 deletions
diff --git a/queue-6.12/alsa-hda-realtek-bass-speaker-fixup-for-asus-um5606k.patch b/queue-6.12/alsa-hda-realtek-bass-speaker-fixup-for-asus-um5606k.patch
new file mode 100644
index 0000000000..5316241eab
--- /dev/null
+++ b/queue-6.12/alsa-hda-realtek-bass-speaker-fixup-for-asus-um5606k.patch
@@ -0,0 +1,43 @@
+From 0c570a043c69df1cc34b0cf32839d7ed57d9940a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Mar 2025 17:25:35 +0700
+Subject: ALSA: hda/realtek: Bass speaker fixup for ASUS UM5606KA
+
+From: Andres Traumann <andres.traumann.01@gmail.com>
+
+[ Upstream commit be8cd366beb80c709adbc7688ee72750f5aee3ff ]
+
+This patch applies the ALC294 bass speaker fixup (ALC294_FIXUP_BASS_SPEAKER_15),
+previously introduced in commit a7df7f909cec ("ALSA: hda: improve bass
+speaker support for ASUS Zenbook UM5606WA"), to the ASUS Zenbook UM5606KA.
+This hardware configuration matches ASUS Zenbook UM5606WA, where DAC NID
+0x06 was removed from the bass speaker (NID 0x15), routing both speaker
+pins to DAC NID 0x03.
+
+This resolves the bass speaker routing issue, ensuring correct audio
+output on ASUS UM5606KA.
+
+Signed-off-by: Andres Traumann <andres.traumann.01@gmail.com>
+Cc: <stable@vger.kernel.org>
+Link: https://patch.msgid.link/20250325102535.8172-1-andres.traumann.01@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 94c5151c456d6..30e9e26c5b2a7 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -10859,6 +10859,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
++ SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15),
+ SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1294, "ASUS B3405CVA", ALC245_FIXUP_CS35L41_SPI_2),
+--
+2.39.5
+
diff --git a/queue-6.12/arm64-dts-rockchip-add-avdd-hdmi-supplies-to-rockpro.patch b/queue-6.12/arm64-dts-rockchip-add-avdd-hdmi-supplies-to-rockpro.patch
new file mode 100644
index 0000000000..46d8526990
--- /dev/null
+++ b/queue-6.12/arm64-dts-rockchip-add-avdd-hdmi-supplies-to-rockpro.patch
@@ -0,0 +1,74 @@
+From 6a1b00a5ef9f98fd2bf1a882f2c1686fae759295 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 2 Mar 2025 19:48:03 +0100
+Subject: arm64: dts: rockchip: Add avdd HDMI supplies to RockPro64 board dtsi
+
+From: Dragan Simic <dsimic@manjaro.org>
+
+[ Upstream commit bd1c959f37f384b477f51572331b0dc828bd009a ]
+
+Add missing "avdd-0v9-supply" and "avdd-1v8-supply" properties to the "hdmi"
+node in the Pine64 RockPro64 board dtsi file. To achieve this, also add the
+associated "vcca_0v9" regulator that produces the 0.9 V supply, [1][2] which
+hasn't been defined previously in the board dtsi file.
+
+This also eliminates the following warnings from the kernel log:
+
+ dwhdmi-rockchip ff940000.hdmi: supply avdd-0v9 not found, using dummy regulator
+ dwhdmi-rockchip ff940000.hdmi: supply avdd-1v8 not found, using dummy regulator
+
+There are no functional changes to the way board works with these additions,
+because the "vcc1v8_dvp" and "vcca_0v9" regulators are always enabled, [1][2]
+but these additions improve the accuracy of hardware description.
+
+These changes apply to the both supported hardware revisions of the Pine64
+RockPro64, i.e. to the production-run revisions 2.0 and 2.1. [1][2]
+
+[1] https://files.pine64.org/doc/rockpro64/rockpro64_v21-SCH.pdf
+[2] https://files.pine64.org/doc/rockpro64/rockpro64_v20-SCH.pdf
+
+Fixes: e4f3fb490967 ("arm64: dts: rockchip: add initial dts support for Rockpro64")
+Cc: stable@vger.kernel.org
+Suggested-by: Diederik de Haas <didi.debian@cknow.org>
+Signed-off-by: Dragan Simic <dsimic@manjaro.org>
+Tested-by: Diederik de Haas <didi.debian@cknow.org>
+Link: https://lore.kernel.org/r/df3d7e8fe74ed5e727e085b18c395260537bb5ac.1740941097.git.dsimic@manjaro.org
+Signed-off-by: Heiko Stuebner <heiko@sntech.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi
+index 11d99d8b34a2b..66d010a9e8c31 100644
+--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi
++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi
+@@ -227,6 +227,16 @@ vcc5v0_usb: vcc5v0-usb {
+ vin-supply = <&vcc12v_dcin>;
+ };
+
++ vcca_0v9: vcca-0v9 {
++ compatible = "regulator-fixed";
++ regulator-name = "vcca_0v9";
++ regulator-always-on;
++ regulator-boot-on;
++ regulator-min-microvolt = <900000>;
++ regulator-max-microvolt = <900000>;
++ vin-supply = <&vcc3v3_sys>;
++ };
++
+ vdd_log: vdd-log {
+ compatible = "pwm-regulator";
+ pwms = <&pwm2 0 25000 1>;
+@@ -312,6 +322,8 @@ &gmac {
+ };
+
+ &hdmi {
++ avdd-0v9-supply = <&vcca_0v9>;
++ avdd-1v8-supply = <&vcc1v8_dvp>;
+ ddc-i2c-bus = <&i2c3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_cec>;
+--
+2.39.5
+
diff --git a/queue-6.12/btrfs-do-proper-folio-cleanup-when-cow_file_range-fa.patch b/queue-6.12/btrfs-do-proper-folio-cleanup-when-cow_file_range-fa.patch
new file mode 100644
index 0000000000..7ad39a914c
--- /dev/null
+++ b/queue-6.12/btrfs-do-proper-folio-cleanup-when-cow_file_range-fa.patch
@@ -0,0 +1,286 @@
+From eeee66aacff2587599644989ed599a608d06cede Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Dec 2024 16:43:58 +1030
+Subject: btrfs: do proper folio cleanup when cow_file_range() failed
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit 06f364284794f149d2abc167c11d556cf20c954b ]
+
+[BUG]
+When testing with COW fixup marked as BUG_ON() (this is involved with the
+new pin_user_pages*() change, which should not result new out-of-band
+dirty pages), I hit a crash triggered by the BUG_ON() from hitting COW
+fixup path.
+
+This BUG_ON() happens just after a failed btrfs_run_delalloc_range():
+
+ BTRFS error (device dm-2): failed to run delalloc range, root 348 ino 405 folio 65536 submit_bitmap 6-15 start 90112 len 106496: -28
+ ------------[ cut here ]------------
+ kernel BUG at fs/btrfs/extent_io.c:1444!
+ Internal error: Oops - BUG: 00000000f2000800 [#1] SMP
+ CPU: 0 UID: 0 PID: 434621 Comm: kworker/u24:8 Tainted: G OE 6.12.0-rc7-custom+ #86
+ Hardware name: QEMU KVM Virtual Machine, BIOS unknown 2/2/2022
+ Workqueue: events_unbound btrfs_async_reclaim_data_space [btrfs]
+ pc : extent_writepage_io+0x2d4/0x308 [btrfs]
+ lr : extent_writepage_io+0x2d4/0x308 [btrfs]
+ Call trace:
+ extent_writepage_io+0x2d4/0x308 [btrfs]
+ extent_writepage+0x218/0x330 [btrfs]
+ extent_write_cache_pages+0x1d4/0x4b0 [btrfs]
+ btrfs_writepages+0x94/0x150 [btrfs]
+ do_writepages+0x74/0x190
+ filemap_fdatawrite_wbc+0x88/0xc8
+ start_delalloc_inodes+0x180/0x3b0 [btrfs]
+ btrfs_start_delalloc_roots+0x174/0x280 [btrfs]
+ shrink_delalloc+0x114/0x280 [btrfs]
+ flush_space+0x250/0x2f8 [btrfs]
+ btrfs_async_reclaim_data_space+0x180/0x228 [btrfs]
+ process_one_work+0x164/0x408
+ worker_thread+0x25c/0x388
+ kthread+0x100/0x118
+ ret_from_fork+0x10/0x20
+ Code: aa1403e1 9402f3ef aa1403e0 9402f36f (d4210000)
+ ---[ end trace 0000000000000000 ]---
+
+[CAUSE]
+That failure is mostly from cow_file_range(), where we can hit -ENOSPC.
+
+Although the -ENOSPC is already a bug related to our space reservation
+code, let's just focus on the error handling.
+
+For example, we have the following dirty range [0, 64K) of an inode,
+with 4K sector size and 4K page size:
+
+ 0 16K 32K 48K 64K
+ |///////////////////////////////////////|
+ |#######################################|
+
+Where |///| means page are still dirty, and |###| means the extent io
+tree has EXTENT_DELALLOC flag.
+
+- Enter extent_writepage() for page 0
+
+- Enter btrfs_run_delalloc_range() for range [0, 64K)
+
+- Enter cow_file_range() for range [0, 64K)
+
+- Function btrfs_reserve_extent() only reserved one 16K extent
+ So we created extent map and ordered extent for range [0, 16K)
+
+ 0 16K 32K 48K 64K
+ |////////|//////////////////////////////|
+ |<- OE ->|##############################|
+
+ And range [0, 16K) has its delalloc flag cleared.
+ But since we haven't yet submit any bio, involved 4 pages are still
+ dirty.
+
+- Function btrfs_reserve_extent() returns with -ENOSPC
+ Now we have to run error cleanup, which will clear all
+ EXTENT_DELALLOC* flags and clear the dirty flags for the remaining
+ ranges:
+
+ 0 16K 32K 48K 64K
+ |////////| |
+ | | |
+
+ Note that range [0, 16K) still has its pages dirty.
+
+- Some time later, writeback is triggered again for the range [0, 16K)
+ since the page range still has dirty flags.
+
+- btrfs_run_delalloc_range() will do nothing because there is no
+ EXTENT_DELALLOC flag.
+
+- extent_writepage_io() finds page 0 has no ordered flag
+ Which falls into the COW fixup path, triggering the BUG_ON().
+
+Unfortunately this error handling bug dates back to the introduction of
+btrfs. Thankfully with the abuse of COW fixup, at least it won't crash
+the kernel.
+
+[FIX]
+Instead of immediately unlocking the extent and folios, we keep the extent
+and folios locked until either erroring out or the whole delalloc range
+finished.
+
+When the whole delalloc range finished without error, we just unlock the
+whole range with PAGE_SET_ORDERED (and PAGE_UNLOCK for !keep_locked
+cases), with EXTENT_DELALLOC and EXTENT_LOCKED cleared.
+And the involved folios will be properly submitted, with their dirty
+flags cleared during submission.
+
+For the error path, it will be a little more complex:
+
+- The range with ordered extent allocated (range (1))
+ We only clear the EXTENT_DELALLOC and EXTENT_LOCKED, as the remaining
+ flags are cleaned up by
+ btrfs_mark_ordered_io_finished()->btrfs_finish_one_ordered().
+
+ For folios we finish the IO (clear dirty, start writeback and
+ immediately finish the writeback) and unlock the folios.
+
+- The range with reserved extent but no ordered extent (range(2))
+- The range we never touched (range(3))
+ For both range (2) and range(3) the behavior is not changed.
+
+Now even if cow_file_range() failed halfway with some successfully
+reserved extents/ordered extents, we will keep all folios clean, so
+there will be no future writeback triggered on them.
+
+CC: stable@vger.kernel.org
+Reviewed-by: Boris Burkov <boris@bur.io>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 77 +++++++++++++++++++++++-------------------------
+ 1 file changed, 37 insertions(+), 40 deletions(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index cc6a350ae6ede..2f0b2cb2ae6e8 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -1408,6 +1408,17 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+
+ alloc_hint = btrfs_get_extent_allocation_hint(inode, start, num_bytes);
+
++ /*
++ * We're not doing compressed IO, don't unlock the first page (which
++ * the caller expects to stay locked), don't clear any dirty bits and
++ * don't set any writeback bits.
++ *
++ * Do set the Ordered (Private2) bit so we know this page was properly
++ * setup for writepage.
++ */
++ page_ops = (keep_locked ? 0 : PAGE_UNLOCK);
++ page_ops |= PAGE_SET_ORDERED;
++
+ /*
+ * Relocation relies on the relocated extents to have exactly the same
+ * size as the original extents. Normally writeback for relocation data
+@@ -1470,6 +1481,10 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+ file_extent.offset = 0;
+ file_extent.compression = BTRFS_COMPRESS_NONE;
+
++ /*
++ * Locked range will be released either during error clean up or
++ * after the whole range is finished.
++ */
+ lock_extent(&inode->io_tree, start, start + ram_size - 1,
+ &cached);
+
+@@ -1515,27 +1530,12 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+
+ btrfs_dec_block_group_reservations(fs_info, ins.objectid);
+
+- /*
+- * We're not doing compressed IO, don't unlock the first page
+- * (which the caller expects to stay locked), don't clear any
+- * dirty bits and don't set any writeback bits
+- *
+- * Do set the Ordered (Private2) bit so we know this page was
+- * properly setup for writepage.
+- */
+- page_ops = (keep_locked ? 0 : PAGE_UNLOCK);
+- page_ops |= PAGE_SET_ORDERED;
+-
+- extent_clear_unlock_delalloc(inode, start, start + ram_size - 1,
+- locked_folio, &cached,
+- EXTENT_LOCKED | EXTENT_DELALLOC,
+- page_ops);
+- if (num_bytes < cur_alloc_size)
++ if (num_bytes < ram_size)
+ num_bytes = 0;
+ else
+- num_bytes -= cur_alloc_size;
++ num_bytes -= ram_size;
+ alloc_hint = ins.objectid + ins.offset;
+- start += cur_alloc_size;
++ start += ram_size;
+ extent_reserved = false;
+
+ /*
+@@ -1546,6 +1546,8 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+ if (ret)
+ goto out_unlock;
+ }
++ extent_clear_unlock_delalloc(inode, orig_start, end, locked_folio, &cached,
++ EXTENT_LOCKED | EXTENT_DELALLOC, page_ops);
+ done:
+ if (done_offset)
+ *done_offset = end;
+@@ -1561,40 +1563,35 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+ * Now, we have three regions to clean up:
+ *
+ * |-------(1)----|---(2)---|-------------(3)----------|
+- * `- orig_start `- start `- start + cur_alloc_size `- end
++ * `- orig_start `- start `- start + ram_size `- end
+ *
+ * We process each region below.
+ */
+
+- clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DELALLOC_NEW |
+- EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV;
+- page_ops = PAGE_UNLOCK | PAGE_START_WRITEBACK | PAGE_END_WRITEBACK;
+-
+ /*
+ * For the range (1). We have already instantiated the ordered extents
+ * for this region. They are cleaned up by
+ * btrfs_cleanup_ordered_extents() in e.g,
+- * btrfs_run_delalloc_range(). EXTENT_LOCKED | EXTENT_DELALLOC are
+- * already cleared in the above loop. And, EXTENT_DELALLOC_NEW |
+- * EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV are handled by the cleanup
+- * function.
++ * btrfs_run_delalloc_range().
++ * EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV
++ * are also handled by the cleanup function.
+ *
+- * However, in case of @keep_locked, we still need to unlock the pages
+- * (except @locked_folio) to ensure all the pages are unlocked.
++ * So here we only clear EXTENT_LOCKED and EXTENT_DELALLOC flag, and
++ * finish the writeback of the involved folios, which will be never submitted.
+ */
+- if (keep_locked && orig_start < start) {
++ if (orig_start < start) {
++ clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC;
++ page_ops = PAGE_UNLOCK | PAGE_START_WRITEBACK | PAGE_END_WRITEBACK;
++
+ if (!locked_folio)
+ mapping_set_error(inode->vfs_inode.i_mapping, ret);
+ extent_clear_unlock_delalloc(inode, orig_start, start - 1,
+- locked_folio, NULL, 0, page_ops);
++ locked_folio, NULL, clear_bits, page_ops);
+ }
+
+- /*
+- * At this point we're unlocked, we want to make sure we're only
+- * clearing these flags under the extent lock, so lock the rest of the
+- * range and clear everything up.
+- */
+- lock_extent(&inode->io_tree, start, end, NULL);
++ clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DELALLOC_NEW |
++ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV;
++ page_ops = PAGE_UNLOCK | PAGE_START_WRITEBACK | PAGE_END_WRITEBACK;
+
+ /*
+ * For the range (2). If we reserved an extent for our delalloc range
+@@ -1608,11 +1605,11 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+ */
+ if (extent_reserved) {
+ extent_clear_unlock_delalloc(inode, start,
+- start + cur_alloc_size - 1,
++ start + ram_size - 1,
+ locked_folio, &cached, clear_bits,
+ page_ops);
+- btrfs_qgroup_free_data(inode, NULL, start, cur_alloc_size, NULL);
+- start += cur_alloc_size;
++ btrfs_qgroup_free_data(inode, NULL, start, ram_size, NULL);
++ start += ram_size;
+ }
+
+ /*
+--
+2.39.5
+
diff --git a/queue-6.12/btrfs-do-regular-iput-instead-of-delayed-iput-during.patch b/queue-6.12/btrfs-do-regular-iput-instead-of-delayed-iput-during.patch
new file mode 100644
index 0000000000..e15489786e
--- /dev/null
+++ b/queue-6.12/btrfs-do-regular-iput-instead-of-delayed-iput-during.patch
@@ -0,0 +1,47 @@
+From be5739ee406bd78b101a05930003c47cc18927bb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 11:11:29 +0000
+Subject: btrfs: do regular iput instead of delayed iput during extent map
+ shrinking
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 15b3b3254d1453a8db038b7d44b311a2d6c71f98 ]
+
+The extent map shrinker now runs in the system unbound workqueue and no
+longer in kswapd context so it can directly do an iput() on inodes even
+if that blocks or needs to acquire any lock (we aren't holding any locks
+when requesting the delayed iput from the shrinker). So we don't need to
+add a delayed iput, wake up the cleaner and delegate the iput() to the
+cleaner, which also adds extra contention on the spinlock that protects
+the delayed iputs list.
+
+Reported-by: Ivan Shapovalov <intelfx@intelfx.name>
+Tested-by: Ivan Shapovalov <intelfx@intelfx.name>
+Link: https://lore.kernel.org/linux-btrfs/0414d690ac5680d0d77dfc930606cdc36e42e12f.camel@intelfx.name/
+CC: stable@vger.kernel.org # 6.12+
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_map.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
+index 61477cb69a6fd..93043edc8ff93 100644
+--- a/fs/btrfs/extent_map.c
++++ b/fs/btrfs/extent_map.c
+@@ -1261,7 +1261,7 @@ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx
+
+ min_ino = btrfs_ino(inode) + 1;
+ ctx->last_ino = btrfs_ino(inode);
+- btrfs_add_delayed_iput(inode);
++ iput(&inode->vfs_inode);
+
+ if (ctx->scanned >= ctx->nr_to_scan ||
+ btrfs_fs_closing(inode->root->fs_info))
+--
+2.39.5
+
diff --git a/queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch b/queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch
new file mode 100644
index 0000000000..a27a16bcdf
--- /dev/null
+++ b/queue-6.12/btrfs-fix-use-after-free-on-inode-when-scanning-root.patch
@@ -0,0 +1,54 @@
+From 5d075b4c9c1810fc58c42a4fa5292e74ba3f5c64 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Jul 2025 19:02:58 -0400
+Subject: btrfs: fix use-after-free on inode when scanning root during em
+ shrinking
+
+[ Upstream commit 59f37036bb7ab3d554c24abc856aabca01126414 ]
+
+At btrfs_scan_root() we are accessing the inode's root (and fs_info) in a
+call to btrfs_fs_closing() after we have scheduled the inode for a delayed
+iput, and that can result in a use-after-free on the inode in case the
+cleaner kthread does the iput before we dereference the inode in the call
+to btrfs_fs_closing().
+
+Fix this by using the fs_info stored already in a local variable instead
+of doing inode->root->fs_info.
+
+Fixes: 102044384056 ("btrfs: make the extent map shrinker run asynchronously as a work queue job")
+CC: stable@vger.kernel.org # 6.13+
+Tested-by: Ivan Shapovalov <intelfx@intelfx.name>
+Link: https://lore.kernel.org/linux-btrfs/0414d690ac5680d0d77dfc930606cdc36e42e12f.camel@intelfx.name/
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_map.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
+index 93043edc8ff93..36af9aa9aab13 100644
+--- a/fs/btrfs/extent_map.c
++++ b/fs/btrfs/extent_map.c
+@@ -1250,6 +1250,7 @@ static struct btrfs_inode *find_first_inode_to_shrink(struct btrfs_root *root,
+
+ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx *ctx)
+ {
++ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_inode *inode;
+ long nr_dropped = 0;
+ u64 min_ino = ctx->last_ino + 1;
+@@ -1264,7 +1265,7 @@ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx
+ iput(&inode->vfs_inode);
+
+ if (ctx->scanned >= ctx->nr_to_scan ||
+- btrfs_fs_closing(inode->root->fs_info))
++ btrfs_fs_closing(fs_info))
+ break;
+
+ cond_resched();
+--
+2.39.5
+
diff --git a/queue-6.12/btrfs-make-the-extent-map-shrinker-run-asynchronousl.patch b/queue-6.12/btrfs-make-the-extent-map-shrinker-run-asynchronousl.patch
new file mode 100644
index 0000000000..cff2e2ea54
--- /dev/null
+++ b/queue-6.12/btrfs-make-the-extent-map-shrinker-run-asynchronousl.patch
@@ -0,0 +1,243 @@
+From ff155cff3944f92ed4eebed0e2d6f093415a2126 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Aug 2024 15:23:32 +0100
+Subject: btrfs: make the extent map shrinker run asynchronously as a work
+ queue job
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 1020443840569535f6025a855958f07ea3eebf71 ]
+
+Currently the extent map shrinker is run synchronously for kswapd tasks
+that end up calling the fs shrinker (fs/super.c:super_cache_scan()).
+This has some disadvantages and for some heavy workloads with memory
+pressure it can cause some delays and stalls that make a machine
+unresponsive for some periods. This happens because:
+
+1) We can have several kswapd tasks on machines with multiple NUMA zones,
+ and running the extent map shrinker concurrently can cause high
+ contention on some spin locks, namely the spin locks that protect
+ the radix tree that tracks roots, the per root xarray that tracks
+ open inodes and the list of delayed iputs. This not only delays the
+ shrinker but also causes high CPU consumption and makes the task
+ running the shrinker monopolize a core, resulting in the symptoms
+ of an unresponsive system. This was noted in previous commits such as
+ commit ae1e766f623f ("btrfs: only run the extent map shrinker from
+ kswapd tasks");
+
+2) The extent map shrinker's iteration over inodes can often be slow, even
+ after changing the data structure that tracks open inodes for a root
+ from a red black tree (up to kernel 6.10) to an xarray (kernel 6.10+).
+ The transition to the xarray while it made things a bit faster, it's
+ still somewhat slow - for example in a test scenario with 10000 inodes
+ that have no extent maps loaded, the extent map shrinker took between
+ 5ms to 8ms, using a release, non-debug kernel. Iterating over the
+ extent maps of an inode can also be slow if have an inode with many
+ thousands of extent maps, since we use a red black tree to track and
+ search extent maps. So having the extent map shrinker run synchronously
+ adds extra delay for other things a kswapd task does.
+
+So make the extent map shrinker run asynchronously as a job for the
+system unbounded workqueue, just like what we do for data and metadata
+space reclaim jobs.
+
+Reviewed-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 2 ++
+ fs/btrfs/extent_map.c | 51 ++++++++++++++++++++++++++++++++++++-------
+ fs/btrfs/extent_map.h | 3 ++-
+ fs/btrfs/fs.h | 2 ++
+ fs/btrfs/super.c | 13 +++--------
+ 5 files changed, 52 insertions(+), 19 deletions(-)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 96282bf28b19c..e655fa3bfd9be 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -2785,6 +2785,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
+ btrfs_init_scrub(fs_info);
+ btrfs_init_balance(fs_info);
+ btrfs_init_async_reclaim_work(fs_info);
++ btrfs_init_extent_map_shrinker_work(fs_info);
+
+ rwlock_init(&fs_info->block_group_cache_lock);
+ fs_info->block_group_cache_tree = RB_ROOT_CACHED;
+@@ -4334,6 +4335,7 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
+ cancel_work_sync(&fs_info->async_reclaim_work);
+ cancel_work_sync(&fs_info->async_data_reclaim_work);
+ cancel_work_sync(&fs_info->preempt_reclaim_work);
++ cancel_work_sync(&fs_info->extent_map_shrinker_work);
+
+ /* Cancel or finish ongoing discard work */
+ btrfs_discard_cleanup(fs_info);
+diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
+index d67abf5f97a77..61477cb69a6fd 100644
+--- a/fs/btrfs/extent_map.c
++++ b/fs/btrfs/extent_map.c
+@@ -1128,7 +1128,8 @@ struct btrfs_em_shrink_ctx {
+
+ static long btrfs_scan_inode(struct btrfs_inode *inode, struct btrfs_em_shrink_ctx *ctx)
+ {
+- const u64 cur_fs_gen = btrfs_get_fs_generation(inode->root->fs_info);
++ struct btrfs_fs_info *fs_info = inode->root->fs_info;
++ const u64 cur_fs_gen = btrfs_get_fs_generation(fs_info);
+ struct extent_map_tree *tree = &inode->extent_tree;
+ long nr_dropped = 0;
+ struct rb_node *node;
+@@ -1187,7 +1188,8 @@ static long btrfs_scan_inode(struct btrfs_inode *inode, struct btrfs_em_shrink_c
+ * lock. This is to avoid slowing other tasks trying to take the
+ * lock.
+ */
+- if (need_resched() || rwlock_needbreak(&tree->lock))
++ if (need_resched() || rwlock_needbreak(&tree->lock) ||
++ btrfs_fs_closing(fs_info))
+ break;
+ node = next;
+ }
+@@ -1261,7 +1263,8 @@ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx
+ ctx->last_ino = btrfs_ino(inode);
+ btrfs_add_delayed_iput(inode);
+
+- if (ctx->scanned >= ctx->nr_to_scan)
++ if (ctx->scanned >= ctx->nr_to_scan ||
++ btrfs_fs_closing(inode->root->fs_info))
+ break;
+
+ cond_resched();
+@@ -1290,16 +1293,19 @@ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx
+ return nr_dropped;
+ }
+
+-long btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan)
++static void btrfs_extent_map_shrinker_worker(struct work_struct *work)
+ {
++ struct btrfs_fs_info *fs_info;
+ struct btrfs_em_shrink_ctx ctx;
+ u64 start_root_id;
+ u64 next_root_id;
+ bool cycled = false;
+ long nr_dropped = 0;
+
++ fs_info = container_of(work, struct btrfs_fs_info, extent_map_shrinker_work);
++
+ ctx.scanned = 0;
+- ctx.nr_to_scan = nr_to_scan;
++ ctx.nr_to_scan = atomic64_read(&fs_info->extent_map_shrinker_nr_to_scan);
+
+ /*
+ * In case we have multiple tasks running this shrinker, make the next
+@@ -1317,12 +1323,12 @@ long btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan)
+ if (trace_btrfs_extent_map_shrinker_scan_enter_enabled()) {
+ s64 nr = percpu_counter_sum_positive(&fs_info->evictable_extent_maps);
+
+- trace_btrfs_extent_map_shrinker_scan_enter(fs_info, nr_to_scan,
++ trace_btrfs_extent_map_shrinker_scan_enter(fs_info, ctx.nr_to_scan,
+ nr, ctx.last_root,
+ ctx.last_ino);
+ }
+
+- while (ctx.scanned < ctx.nr_to_scan) {
++ while (ctx.scanned < ctx.nr_to_scan && !btrfs_fs_closing(fs_info)) {
+ struct btrfs_root *root;
+ unsigned long count;
+
+@@ -1380,5 +1386,34 @@ long btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan)
+ ctx.last_ino);
+ }
+
+- return nr_dropped;
++ atomic64_set(&fs_info->extent_map_shrinker_nr_to_scan, 0);
++}
++
++void btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan)
++{
++ /*
++ * Do nothing if the shrinker is already running. In case of high memory
++ * pressure we can have a lot of tasks calling us and all passing the
++ * same nr_to_scan value, but in reality we may need only to free
++ * nr_to_scan extent maps (or less). In case we need to free more than
++ * that, we will be called again by the fs shrinker, so no worries about
++ * not doing enough work to reclaim memory from extent maps.
++ * We can also be repeatedly called with the same nr_to_scan value
++ * simply because the shrinker runs asynchronously and multiple calls
++ * to this function are made before the shrinker does enough progress.
++ *
++ * That's why we set the atomic counter to nr_to_scan only if its
++ * current value is zero, instead of incrementing the counter by
++ * nr_to_scan.
++ */
++ if (atomic64_cmpxchg(&fs_info->extent_map_shrinker_nr_to_scan, 0, nr_to_scan) != 0)
++ return;
++
++ queue_work(system_unbound_wq, &fs_info->extent_map_shrinker_work);
++}
++
++void btrfs_init_extent_map_shrinker_work(struct btrfs_fs_info *fs_info)
++{
++ atomic64_set(&fs_info->extent_map_shrinker_nr_to_scan, 0);
++ INIT_WORK(&fs_info->extent_map_shrinker_work, btrfs_extent_map_shrinker_worker);
+ }
+diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
+index 5154a8f1d26c9..cd123b266b641 100644
+--- a/fs/btrfs/extent_map.h
++++ b/fs/btrfs/extent_map.h
+@@ -189,6 +189,7 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode,
+ int btrfs_replace_extent_map_range(struct btrfs_inode *inode,
+ struct extent_map *new_em,
+ bool modified);
+-long btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan);
++void btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan);
++void btrfs_init_extent_map_shrinker_work(struct btrfs_fs_info *fs_info);
+
+ #endif
+diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h
+index bb822e425d7fa..374843aca60d8 100644
+--- a/fs/btrfs/fs.h
++++ b/fs/btrfs/fs.h
+@@ -639,6 +639,8 @@ struct btrfs_fs_info {
+ spinlock_t extent_map_shrinker_lock;
+ u64 extent_map_shrinker_last_root;
+ u64 extent_map_shrinker_last_ino;
++ atomic64_t extent_map_shrinker_nr_to_scan;
++ struct work_struct extent_map_shrinker_work;
+
+ /* Protected by 'trans_lock'. */
+ struct list_head dirty_cowonly_roots;
+diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
+index bcb8def4ade20..6119a06b05693 100644
+--- a/fs/btrfs/super.c
++++ b/fs/btrfs/super.c
+@@ -28,7 +28,6 @@
+ #include <linux/btrfs.h>
+ #include <linux/security.h>
+ #include <linux/fs_parser.h>
+-#include <linux/swap.h>
+ #include "messages.h"
+ #include "delayed-inode.h"
+ #include "ctree.h"
+@@ -2399,16 +2398,10 @@ static long btrfs_free_cached_objects(struct super_block *sb, struct shrink_cont
+ const long nr_to_scan = min_t(unsigned long, LONG_MAX, sc->nr_to_scan);
+ struct btrfs_fs_info *fs_info = btrfs_sb(sb);
+
+- /*
+- * We may be called from any task trying to allocate memory and we don't
+- * want to slow it down with scanning and dropping extent maps. It would
+- * also cause heavy lock contention if many tasks concurrently enter
+- * here. Therefore only allow kswapd tasks to scan and drop extent maps.
+- */
+- if (!current_is_kswapd())
+- return 0;
++ btrfs_free_extent_maps(fs_info, nr_to_scan);
+
+- return btrfs_free_extent_maps(fs_info, nr_to_scan);
++ /* The extent map shrinker runs asynchronously, so always return 0. */
++ return 0;
+ }
+
+ static const struct super_operations btrfs_super_ops = {
+--
+2.39.5
+
diff --git a/queue-6.12/btrfs-skip-inodes-without-loaded-extent-maps-when-sh.patch b/queue-6.12/btrfs-skip-inodes-without-loaded-extent-maps-when-sh.patch
new file mode 100644
index 0000000000..91401e4adb
--- /dev/null
+++ b/queue-6.12/btrfs-skip-inodes-without-loaded-extent-maps-when-sh.patch
@@ -0,0 +1,161 @@
+From 6f7096b21055313b16be91b99f0c4fe1a05d9449 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 11:04:15 +0000
+Subject: btrfs: skip inodes without loaded extent maps when shrinking extent
+ maps
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit c6c9c4d56483d941f567eb921434c25fc6086dfa ]
+
+If there are inodes that don't have any loaded extent maps, we end up
+grabbing a reference on them and later adding a delayed iput, which wakes
+up the cleaner and makes it do unnecessary work. This is common when for
+example the inodes were open only to run stat(2) or all their extent maps
+were already released through the folio release callback
+(btrfs_release_folio()) or released by a previous run of the shrinker, or
+directories which never have extent maps.
+
+Reported-by: Ivan Shapovalov <intelfx@intelfx.name>
+Tested-by: Ivan Shapovalov <intelfx@intelfx.name>
+Link: https://lore.kernel.org/linux-btrfs/0414d690ac5680d0d77dfc930606cdc36e42e12f.camel@intelfx.name/
+CC: stable@vger.kernel.org # 6.13+
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent_map.c | 78 +++++++++++++++++++++++++++++++------------
+ 1 file changed, 57 insertions(+), 21 deletions(-)
+
+diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
+index 1d93e1202c339..d67abf5f97a77 100644
+--- a/fs/btrfs/extent_map.c
++++ b/fs/btrfs/extent_map.c
+@@ -1133,6 +1133,8 @@ static long btrfs_scan_inode(struct btrfs_inode *inode, struct btrfs_em_shrink_c
+ long nr_dropped = 0;
+ struct rb_node *node;
+
++ lockdep_assert_held_write(&tree->lock);
++
+ /*
+ * Take the mmap lock so that we serialize with the inode logging phase
+ * of fsync because we may need to set the full sync flag on the inode,
+@@ -1144,28 +1146,12 @@ static long btrfs_scan_inode(struct btrfs_inode *inode, struct btrfs_em_shrink_c
+ * to find new extents, which may not be there yet because ordered
+ * extents haven't completed yet.
+ *
+- * We also do a try lock because otherwise we could deadlock. This is
+- * because the shrinker for this filesystem may be invoked while we are
+- * in a path that is holding the mmap lock in write mode. For example in
+- * a reflink operation while COWing an extent buffer, when allocating
+- * pages for a new extent buffer and under memory pressure, the shrinker
+- * may be invoked, and therefore we would deadlock by attempting to read
+- * lock the mmap lock while we are holding already a write lock on it.
++ * We also do a try lock because we don't want to block for too long and
++ * we are holding the extent map tree's lock in write mode.
+ */
+ if (!down_read_trylock(&inode->i_mmap_lock))
+ return 0;
+
+- /*
+- * We want to be fast so if the lock is busy we don't want to spend time
+- * waiting for it - either some task is about to do IO for the inode or
+- * we may have another task shrinking extent maps, here in this code, so
+- * skip this inode.
+- */
+- if (!write_trylock(&tree->lock)) {
+- up_read(&inode->i_mmap_lock);
+- return 0;
+- }
+-
+ node = rb_first(&tree->root);
+ while (node) {
+ struct rb_node *next = rb_next(node);
+@@ -1205,21 +1191,71 @@ static long btrfs_scan_inode(struct btrfs_inode *inode, struct btrfs_em_shrink_c
+ break;
+ node = next;
+ }
+- write_unlock(&tree->lock);
+ up_read(&inode->i_mmap_lock);
+
+ return nr_dropped;
+ }
+
++static struct btrfs_inode *find_first_inode_to_shrink(struct btrfs_root *root,
++ u64 min_ino)
++{
++ struct btrfs_inode *inode;
++ unsigned long from = min_ino;
++
++ xa_lock(&root->inodes);
++ while (true) {
++ struct extent_map_tree *tree;
++
++ inode = xa_find(&root->inodes, &from, ULONG_MAX, XA_PRESENT);
++ if (!inode)
++ break;
++
++ tree = &inode->extent_tree;
++
++ /*
++ * We want to be fast so if the lock is busy we don't want to
++ * spend time waiting for it (some task is about to do IO for
++ * the inode).
++ */
++ if (!write_trylock(&tree->lock))
++ goto next;
++
++ /*
++ * Skip inode if it doesn't have loaded extent maps, so we avoid
++ * getting a reference and doing an iput later. This includes
++ * cases like files that were opened for things like stat(2), or
++ * files with all extent maps previously released through the
++ * release folio callback (btrfs_release_folio()) or released in
++ * a previous run, or directories which never have extent maps.
++ */
++ if (RB_EMPTY_ROOT(&tree->root)) {
++ write_unlock(&tree->lock);
++ goto next;
++ }
++
++ if (igrab(&inode->vfs_inode))
++ break;
++
++ write_unlock(&tree->lock);
++next:
++ from = btrfs_ino(inode) + 1;
++ cond_resched_lock(&root->inodes.xa_lock);
++ }
++ xa_unlock(&root->inodes);
++
++ return inode;
++}
++
+ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx *ctx)
+ {
+ struct btrfs_inode *inode;
+ long nr_dropped = 0;
+ u64 min_ino = ctx->last_ino + 1;
+
+- inode = btrfs_find_first_inode(root, min_ino);
++ inode = find_first_inode_to_shrink(root, min_ino);
+ while (inode) {
+ nr_dropped += btrfs_scan_inode(inode, ctx);
++ write_unlock(&inode->extent_tree.lock);
+
+ min_ino = btrfs_ino(inode) + 1;
+ ctx->last_ino = btrfs_ino(inode);
+@@ -1230,7 +1266,7 @@ static long btrfs_scan_root(struct btrfs_root *root, struct btrfs_em_shrink_ctx
+
+ cond_resched();
+
+- inode = btrfs_find_first_inode(root, min_ino);
++ inode = find_first_inode_to_shrink(root, min_ino);
+ }
+
+ if (inode) {
+--
+2.39.5
+
diff --git a/queue-6.12/btrfs-zoned-fix-extent-range-end-unlock-in-cow_file_.patch b/queue-6.12/btrfs-zoned-fix-extent-range-end-unlock-in-cow_file_.patch
new file mode 100644
index 0000000000..a02c3dc14c
--- /dev/null
+++ b/queue-6.12/btrfs-zoned-fix-extent-range-end-unlock-in-cow_file_.patch
@@ -0,0 +1,135 @@
+From 6ed6b3b95a677a97677044d859cb750662af6bff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 16:02:11 +0900
+Subject: btrfs: zoned: fix extent range end unlock in cow_file_range()
+
+From: Naohiro Aota <naohiro.aota@wdc.com>
+
+[ Upstream commit 5a4041f2c47247575a6c2e53ce14f7b0ac946c33 ]
+
+Running generic/751 on the for-next branch often results in a hang like
+below. They are both stack by locking an extent. This suggests someone
+forget to unlock an extent.
+
+ INFO: task kworker/u128:1:12 blocked for more than 323 seconds.
+ Not tainted 6.13.0-BTRFS-ZNS+ #503
+ "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+ task:kworker/u128:1 state:D stack:0 pid:12 tgid:12 ppid:2 flags:0x00004000
+ Workqueue: btrfs-fixup btrfs_work_helper [btrfs]
+ Call Trace:
+ <TASK>
+ __schedule+0x534/0xdd0
+ schedule+0x39/0x140
+ __lock_extent+0x31b/0x380 [btrfs]
+ ? __pfx_autoremove_wake_function+0x10/0x10
+ btrfs_writepage_fixup_worker+0xf1/0x3a0 [btrfs]
+ btrfs_work_helper+0xff/0x480 [btrfs]
+ ? lock_release+0x178/0x2c0
+ process_one_work+0x1ee/0x570
+ ? srso_return_thunk+0x5/0x5f
+ worker_thread+0x1d1/0x3b0
+ ? __pfx_worker_thread+0x10/0x10
+ kthread+0x10b/0x230
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork+0x30/0x50
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork_asm+0x1a/0x30
+ </TASK>
+ INFO: task kworker/u134:0:184 blocked for more than 323 seconds.
+ Not tainted 6.13.0-BTRFS-ZNS+ #503
+ "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+ task:kworker/u134:0 state:D stack:0 pid:184 tgid:184 ppid:2 flags:0x00004000
+ Workqueue: writeback wb_workfn (flush-btrfs-4)
+ Call Trace:
+ <TASK>
+ __schedule+0x534/0xdd0
+ schedule+0x39/0x140
+ __lock_extent+0x31b/0x380 [btrfs]
+ ? __pfx_autoremove_wake_function+0x10/0x10
+ find_lock_delalloc_range+0xdb/0x260 [btrfs]
+ writepage_delalloc+0x12f/0x500 [btrfs]
+ ? srso_return_thunk+0x5/0x5f
+ extent_write_cache_pages+0x232/0x840 [btrfs]
+ btrfs_writepages+0x72/0x130 [btrfs]
+ do_writepages+0xe7/0x260
+ ? srso_return_thunk+0x5/0x5f
+ ? lock_acquire+0xd2/0x300
+ ? srso_return_thunk+0x5/0x5f
+ ? find_held_lock+0x2b/0x80
+ ? wbc_attach_and_unlock_inode.part.0+0x102/0x250
+ ? wbc_attach_and_unlock_inode.part.0+0x102/0x250
+ __writeback_single_inode+0x5c/0x4b0
+ writeback_sb_inodes+0x22d/0x550
+ __writeback_inodes_wb+0x4c/0xe0
+ wb_writeback+0x2f6/0x3f0
+ wb_workfn+0x32a/0x510
+ process_one_work+0x1ee/0x570
+ ? srso_return_thunk+0x5/0x5f
+ worker_thread+0x1d1/0x3b0
+ ? __pfx_worker_thread+0x10/0x10
+ kthread+0x10b/0x230
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork+0x30/0x50
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork_asm+0x1a/0x30
+ </TASK>
+
+This happens because we have another success path for the zoned mode. When
+there is no active zone available, btrfs_reserve_extent() returns
+-EAGAIN. In this case, we have two reactions.
+
+(1) If the given range is never allocated, we can only wait for someone
+ to finish a zone, so wait on BTRFS_FS_NEED_ZONE_FINISH bit and retry
+ afterward.
+
+(2) Or, if some allocations are already done, we must bail out and let
+ the caller to send IOs for the allocation. This is because these IOs
+ may be necessary to finish a zone.
+
+The commit 06f364284794 ("btrfs: do proper folio cleanup when
+cow_file_range() failed") moved the unlock code from the inside of the
+loop to the outside. So, previously, the allocated extents are unlocked
+just after the allocation and so before returning from the function.
+However, they are no longer unlocked on the case (2) above. That caused
+the hang issue.
+
+Fix the issue by modifying the 'end' to the end of the allocated
+range. Then, we can exit the loop and the same unlock code can properly
+handle the case.
+
+Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Tested-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Fixes: 06f364284794 ("btrfs: do proper folio cleanup when cow_file_range() failed")
+CC: stable@vger.kernel.org
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 2f0b2cb2ae6e8..921ec3802648b 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -1463,8 +1463,13 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
+ continue;
+ }
+ if (done_offset) {
+- *done_offset = start - 1;
+- return 0;
++ /*
++ * Move @end to the end of the processed range,
++ * and exit the loop to unlock the processed extents.
++ */
++ end = start - 1;
++ ret = 0;
++ break;
+ }
+ ret = -ENOSPC;
+ }
+--
+2.39.5
+
diff --git a/queue-6.12/drm-amdkfd-fix-instruction-hazard-in-gfx12-trap-hand.patch b/queue-6.12/drm-amdkfd-fix-instruction-hazard-in-gfx12-trap-hand.patch
new file mode 100644
index 0000000000..a35498d35f
--- /dev/null
+++ b/queue-6.12/drm-amdkfd-fix-instruction-hazard-in-gfx12-trap-hand.patch
@@ -0,0 +1,932 @@
+From bf4d4b17e212aba8bcebe5d7cfc657b09166f1e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Feb 2025 16:40:34 -0500
+Subject: drm/amdkfd: Fix instruction hazard in gfx12 trap handler
+
+From: Jay Cornwall <jay.cornwall@amd.com>
+
+[ Upstream commit 424648c3838133f93a34fdfe4f9d5597551e7b3b ]
+
+VALU instructions with SGPR source need wait states to avoid hazard
+with SALU using different SGPR.
+
+v2: Eliminate some hazards to reduce code explosion
+
+Signed-off-by: Jay Cornwall <jay.cornwall@amd.com>
+Reviewed-by: Lancelot Six <lancelot.six@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit 7e0459d453b911435673edd7a86eadc600c63238)
+Cc: stable@vger.kernel.org # 6.12.x
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/amd/amdkfd/cwsr_trap_handler.h | 677 ++++++++++--------
+ .../amd/amdkfd/cwsr_trap_handler_gfx12.asm | 82 ++-
+ 2 files changed, 404 insertions(+), 355 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
+index 7062f12b5b751..6c8c9935a0f2e 100644
+--- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
++++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h
+@@ -3640,7 +3640,7 @@ static const uint32_t cwsr_trap_gfx9_4_3_hex[] = {
+ };
+
+ static const uint32_t cwsr_trap_gfx12_hex[] = {
+- 0xbfa00001, 0xbfa0024b,
++ 0xbfa00001, 0xbfa002a2,
+ 0xb0804009, 0xb8f8f804,
+ 0x9178ff78, 0x00008c00,
+ 0xb8fbf811, 0x8b6eff78,
+@@ -3714,7 +3714,15 @@ static const uint32_t cwsr_trap_gfx12_hex[] = {
+ 0x00011677, 0xd7610000,
+ 0x00011a79, 0xd7610000,
+ 0x00011c7e, 0xd7610000,
+- 0x00011e7f, 0xbefe00ff,
++ 0x00011e7f, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xbefe00ff,
+ 0x00003fff, 0xbeff0080,
+ 0xee0a407a, 0x000c0000,
+ 0x00004000, 0xd760007a,
+@@ -3751,38 +3759,46 @@ static const uint32_t cwsr_trap_gfx12_hex[] = {
+ 0x00000200, 0xbef600ff,
+ 0x01000000, 0x7e000280,
+ 0x7e020280, 0x7e040280,
+- 0xbefd0080, 0xbe804ec2,
+- 0xbf94fffe, 0xb8faf804,
+- 0x8b7a847a, 0x91788478,
+- 0x8c787a78, 0xd7610002,
+- 0x0000fa71, 0x807d817d,
+- 0xd7610002, 0x0000fa6c,
+- 0x807d817d, 0x917aff6d,
+- 0x80000000, 0xd7610002,
+- 0x0000fa7a, 0x807d817d,
+- 0xd7610002, 0x0000fa6e,
+- 0x807d817d, 0xd7610002,
+- 0x0000fa6f, 0x807d817d,
+- 0xd7610002, 0x0000fa78,
+- 0x807d817d, 0xb8faf811,
+- 0xd7610002, 0x0000fa7a,
+- 0x807d817d, 0xd7610002,
+- 0x0000fa7b, 0x807d817d,
+- 0xb8f1f801, 0xd7610002,
+- 0x0000fa71, 0x807d817d,
+- 0xb8f1f814, 0xd7610002,
+- 0x0000fa71, 0x807d817d,
+- 0xb8f1f815, 0xd7610002,
+- 0x0000fa71, 0x807d817d,
+- 0xb8f1f812, 0xd7610002,
+- 0x0000fa71, 0x807d817d,
+- 0xb8f1f813, 0xd7610002,
+- 0x0000fa71, 0x807d817d,
++ 0xbe804ec2, 0xbf94fffe,
++ 0xb8faf804, 0x8b7a847a,
++ 0x91788478, 0x8c787a78,
++ 0x917aff6d, 0x80000000,
++ 0xd7610002, 0x00010071,
++ 0xd7610002, 0x0001026c,
++ 0xd7610002, 0x0001047a,
++ 0xd7610002, 0x0001066e,
++ 0xd7610002, 0x0001086f,
++ 0xd7610002, 0x00010a78,
++ 0xd7610002, 0x00010e7b,
++ 0xd8500000, 0x00000000,
++ 0xd8500000, 0x00000000,
++ 0xd8500000, 0x00000000,
++ 0xd8500000, 0x00000000,
++ 0xd8500000, 0x00000000,
++ 0xd8500000, 0x00000000,
++ 0xd8500000, 0x00000000,
++ 0xd8500000, 0x00000000,
++ 0xb8faf811, 0xd7610002,
++ 0x00010c7a, 0xb8faf801,
++ 0xd7610002, 0x0001107a,
++ 0xb8faf814, 0xd7610002,
++ 0x0001127a, 0xb8faf815,
++ 0xd7610002, 0x0001147a,
++ 0xb8faf812, 0xd7610002,
++ 0x0001167a, 0xb8faf813,
++ 0xd7610002, 0x0001187a,
+ 0xb8faf802, 0xd7610002,
+- 0x0000fa7a, 0x807d817d,
+- 0xbefa50c1, 0xbfc70000,
+- 0xd7610002, 0x0000fa7a,
+- 0x807d817d, 0xbefe00ff,
++ 0x00011a7a, 0xbefa50c1,
++ 0xbfc70000, 0xd7610002,
++ 0x00011c7a, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xbefe00ff,
+ 0x0000ffff, 0xbeff0080,
+ 0xc4068070, 0x008ce802,
+ 0x00000000, 0xbefe00c1,
+@@ -3797,329 +3813,356 @@ static const uint32_t cwsr_trap_gfx12_hex[] = {
+ 0xbe824102, 0xbe844104,
+ 0xbe864106, 0xbe884108,
+ 0xbe8a410a, 0xbe8c410c,
+- 0xbe8e410e, 0xd7610002,
+- 0x0000f200, 0x80798179,
+- 0xd7610002, 0x0000f201,
+- 0x80798179, 0xd7610002,
+- 0x0000f202, 0x80798179,
+- 0xd7610002, 0x0000f203,
+- 0x80798179, 0xd7610002,
+- 0x0000f204, 0x80798179,
+- 0xd7610002, 0x0000f205,
+- 0x80798179, 0xd7610002,
+- 0x0000f206, 0x80798179,
+- 0xd7610002, 0x0000f207,
+- 0x80798179, 0xd7610002,
+- 0x0000f208, 0x80798179,
+- 0xd7610002, 0x0000f209,
+- 0x80798179, 0xd7610002,
+- 0x0000f20a, 0x80798179,
+- 0xd7610002, 0x0000f20b,
+- 0x80798179, 0xd7610002,
+- 0x0000f20c, 0x80798179,
+- 0xd7610002, 0x0000f20d,
+- 0x80798179, 0xd7610002,
+- 0x0000f20e, 0x80798179,
+- 0xd7610002, 0x0000f20f,
+- 0x80798179, 0xbf06a079,
+- 0xbfa10007, 0xc4068070,
++ 0xbe8e410e, 0xbf068079,
++ 0xbfa10032, 0xd7610002,
++ 0x00010000, 0xd7610002,
++ 0x00010201, 0xd7610002,
++ 0x00010402, 0xd7610002,
++ 0x00010603, 0xd7610002,
++ 0x00010804, 0xd7610002,
++ 0x00010a05, 0xd7610002,
++ 0x00010c06, 0xd7610002,
++ 0x00010e07, 0xd7610002,
++ 0x00011008, 0xd7610002,
++ 0x00011209, 0xd7610002,
++ 0x0001140a, 0xd7610002,
++ 0x0001160b, 0xd7610002,
++ 0x0001180c, 0xd7610002,
++ 0x00011a0d, 0xd7610002,
++ 0x00011c0e, 0xd7610002,
++ 0x00011e0f, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0x80799079,
++ 0xbfa00038, 0xd7610002,
++ 0x00012000, 0xd7610002,
++ 0x00012201, 0xd7610002,
++ 0x00012402, 0xd7610002,
++ 0x00012603, 0xd7610002,
++ 0x00012804, 0xd7610002,
++ 0x00012a05, 0xd7610002,
++ 0x00012c06, 0xd7610002,
++ 0x00012e07, 0xd7610002,
++ 0x00013008, 0xd7610002,
++ 0x00013209, 0xd7610002,
++ 0x0001340a, 0xd7610002,
++ 0x0001360b, 0xd7610002,
++ 0x0001380c, 0xd7610002,
++ 0x00013a0d, 0xd7610002,
++ 0x00013c0e, 0xd7610002,
++ 0x00013e0f, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0x80799079,
++ 0xc4068070, 0x008ce802,
++ 0x00000000, 0x8070ff70,
++ 0x00000080, 0xbef90080,
++ 0x7e040280, 0x807d907d,
++ 0xbf0aff7d, 0x00000060,
++ 0xbfa2ff88, 0xbe804100,
++ 0xbe824102, 0xbe844104,
++ 0xbe864106, 0xbe884108,
++ 0xbe8a410a, 0xd7610002,
++ 0x00010000, 0xd7610002,
++ 0x00010201, 0xd7610002,
++ 0x00010402, 0xd7610002,
++ 0x00010603, 0xd7610002,
++ 0x00010804, 0xd7610002,
++ 0x00010a05, 0xd7610002,
++ 0x00010c06, 0xd7610002,
++ 0x00010e07, 0xd7610002,
++ 0x00011008, 0xd7610002,
++ 0x00011209, 0xd7610002,
++ 0x0001140a, 0xd7610002,
++ 0x0001160b, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xd8500000,
++ 0x00000000, 0xc4068070,
+ 0x008ce802, 0x00000000,
++ 0xbefe00c1, 0x857d9973,
++ 0x8b7d817d, 0xbf06817d,
++ 0xbfa20002, 0xbeff0080,
++ 0xbfa00001, 0xbeff00c1,
++ 0xb8fb4306, 0x8b7bc17b,
++ 0xbfa10044, 0x8b7aff6d,
++ 0x80000000, 0xbfa10041,
++ 0x847b897b, 0xbef6007b,
++ 0xb8f03b05, 0x80708170,
++ 0xbf0d9973, 0xbfa20002,
++ 0x84708970, 0xbfa00001,
++ 0x84708a70, 0xb8fa1e06,
++ 0x847a8a7a, 0x80707a70,
++ 0x8070ff70, 0x00000200,
+ 0x8070ff70, 0x00000080,
+- 0xbef90080, 0x7e040280,
+- 0x807d907d, 0xbf0aff7d,
+- 0x00000060, 0xbfa2ffbb,
+- 0xbe804100, 0xbe824102,
+- 0xbe844104, 0xbe864106,
+- 0xbe884108, 0xbe8a410a,
+- 0xd7610002, 0x0000f200,
+- 0x80798179, 0xd7610002,
+- 0x0000f201, 0x80798179,
+- 0xd7610002, 0x0000f202,
+- 0x80798179, 0xd7610002,
+- 0x0000f203, 0x80798179,
+- 0xd7610002, 0x0000f204,
+- 0x80798179, 0xd7610002,
+- 0x0000f205, 0x80798179,
+- 0xd7610002, 0x0000f206,
+- 0x80798179, 0xd7610002,
+- 0x0000f207, 0x80798179,
+- 0xd7610002, 0x0000f208,
+- 0x80798179, 0xd7610002,
+- 0x0000f209, 0x80798179,
+- 0xd7610002, 0x0000f20a,
+- 0x80798179, 0xd7610002,
+- 0x0000f20b, 0x80798179,
+- 0xc4068070, 0x008ce802,
+- 0x00000000, 0xbefe00c1,
+- 0x857d9973, 0x8b7d817d,
+- 0xbf06817d, 0xbfa20002,
+- 0xbeff0080, 0xbfa00001,
+- 0xbeff00c1, 0xb8fb4306,
+- 0x8b7bc17b, 0xbfa10044,
+- 0x8b7aff6d, 0x80000000,
+- 0xbfa10041, 0x847b897b,
+- 0xbef6007b, 0xb8f03b05,
+- 0x80708170, 0xbf0d9973,
+- 0xbfa20002, 0x84708970,
+- 0xbfa00001, 0x84708a70,
+- 0xb8fa1e06, 0x847a8a7a,
+- 0x80707a70, 0x8070ff70,
+- 0x00000200, 0x8070ff70,
+- 0x00000080, 0xbef600ff,
+- 0x01000000, 0xd71f0000,
+- 0x000100c1, 0xd7200000,
+- 0x000200c1, 0x16000084,
+- 0x857d9973, 0x8b7d817d,
+- 0xbf06817d, 0xbefd0080,
+- 0xbfa20013, 0xbe8300ff,
+- 0x00000080, 0xbf800000,
+- 0xbf800000, 0xbf800000,
+- 0xd8d80000, 0x01000000,
+- 0xbf8a0000, 0xc4068070,
+- 0x008ce801, 0x00000000,
+- 0x807d037d, 0x80700370,
+- 0xd5250000, 0x0001ff00,
+- 0x00000080, 0xbf0a7b7d,
+- 0xbfa2fff3, 0xbfa00012,
+- 0xbe8300ff, 0x00000100,
++ 0xbef600ff, 0x01000000,
++ 0xd71f0000, 0x000100c1,
++ 0xd7200000, 0x000200c1,
++ 0x16000084, 0x857d9973,
++ 0x8b7d817d, 0xbf06817d,
++ 0xbefd0080, 0xbfa20013,
++ 0xbe8300ff, 0x00000080,
+ 0xbf800000, 0xbf800000,
+ 0xbf800000, 0xd8d80000,
+ 0x01000000, 0xbf8a0000,
+ 0xc4068070, 0x008ce801,
+ 0x00000000, 0x807d037d,
+ 0x80700370, 0xd5250000,
+- 0x0001ff00, 0x00000100,
++ 0x0001ff00, 0x00000080,
+ 0xbf0a7b7d, 0xbfa2fff3,
+- 0xbefe00c1, 0x857d9973,
+- 0x8b7d817d, 0xbf06817d,
+- 0xbfa20004, 0xbef000ff,
+- 0x00000200, 0xbeff0080,
+- 0xbfa00003, 0xbef000ff,
+- 0x00000400, 0xbeff00c1,
+- 0xb8fb3b05, 0x807b817b,
+- 0x847b827b, 0x857d9973,
+- 0x8b7d817d, 0xbf06817d,
+- 0xbfa2001b, 0xbef600ff,
+- 0x01000000, 0xbefd0084,
+- 0xbf0a7b7d, 0xbfa10040,
+- 0x7e008700, 0x7e028701,
+- 0x7e048702, 0x7e068703,
+- 0xc4068070, 0x008ce800,
+- 0x00000000, 0xc4068070,
+- 0x008ce801, 0x00008000,
+- 0xc4068070, 0x008ce802,
+- 0x00010000, 0xc4068070,
+- 0x008ce803, 0x00018000,
+- 0x807d847d, 0x8070ff70,
+- 0x00000200, 0xbf0a7b7d,
+- 0xbfa2ffeb, 0xbfa0002a,
++ 0xbfa00012, 0xbe8300ff,
++ 0x00000100, 0xbf800000,
++ 0xbf800000, 0xbf800000,
++ 0xd8d80000, 0x01000000,
++ 0xbf8a0000, 0xc4068070,
++ 0x008ce801, 0x00000000,
++ 0x807d037d, 0x80700370,
++ 0xd5250000, 0x0001ff00,
++ 0x00000100, 0xbf0a7b7d,
++ 0xbfa2fff3, 0xbefe00c1,
++ 0x857d9973, 0x8b7d817d,
++ 0xbf06817d, 0xbfa20004,
++ 0xbef000ff, 0x00000200,
++ 0xbeff0080, 0xbfa00003,
++ 0xbef000ff, 0x00000400,
++ 0xbeff00c1, 0xb8fb3b05,
++ 0x807b817b, 0x847b827b,
++ 0x857d9973, 0x8b7d817d,
++ 0xbf06817d, 0xbfa2001b,
+ 0xbef600ff, 0x01000000,
+ 0xbefd0084, 0xbf0a7b7d,
+- 0xbfa10015, 0x7e008700,
++ 0xbfa10040, 0x7e008700,
+ 0x7e028701, 0x7e048702,
+ 0x7e068703, 0xc4068070,
+ 0x008ce800, 0x00000000,
+ 0xc4068070, 0x008ce801,
+- 0x00010000, 0xc4068070,
+- 0x008ce802, 0x00020000,
++ 0x00008000, 0xc4068070,
++ 0x008ce802, 0x00010000,
+ 0xc4068070, 0x008ce803,
+- 0x00030000, 0x807d847d,
+- 0x8070ff70, 0x00000400,
++ 0x00018000, 0x807d847d,
++ 0x8070ff70, 0x00000200,
+ 0xbf0a7b7d, 0xbfa2ffeb,
+- 0xb8fb1e06, 0x8b7bc17b,
+- 0xbfa1000d, 0x847b837b,
+- 0x807b7d7b, 0xbefe00c1,
+- 0xbeff0080, 0x7e008700,
++ 0xbfa0002a, 0xbef600ff,
++ 0x01000000, 0xbefd0084,
++ 0xbf0a7b7d, 0xbfa10015,
++ 0x7e008700, 0x7e028701,
++ 0x7e048702, 0x7e068703,
+ 0xc4068070, 0x008ce800,
+- 0x00000000, 0x807d817d,
+- 0x8070ff70, 0x00000080,
+- 0xbf0a7b7d, 0xbfa2fff7,
+- 0xbfa0016e, 0xbef4007e,
+- 0x8b75ff7f, 0x0000ffff,
+- 0x8c75ff75, 0x00040000,
+- 0xbef60080, 0xbef700ff,
+- 0x10807fac, 0xbef1007f,
+- 0xb8f20742, 0x84729972,
+- 0x8b6eff7f, 0x04000000,
+- 0xbfa1003b, 0xbefe00c1,
+- 0x857d9972, 0x8b7d817d,
+- 0xbf06817d, 0xbfa20002,
+- 0xbeff0080, 0xbfa00001,
+- 0xbeff00c1, 0xb8ef4306,
+- 0x8b6fc16f, 0xbfa10030,
+- 0x846f896f, 0xbef6006f,
++ 0x00000000, 0xc4068070,
++ 0x008ce801, 0x00010000,
++ 0xc4068070, 0x008ce802,
++ 0x00020000, 0xc4068070,
++ 0x008ce803, 0x00030000,
++ 0x807d847d, 0x8070ff70,
++ 0x00000400, 0xbf0a7b7d,
++ 0xbfa2ffeb, 0xb8fb1e06,
++ 0x8b7bc17b, 0xbfa1000d,
++ 0x847b837b, 0x807b7d7b,
++ 0xbefe00c1, 0xbeff0080,
++ 0x7e008700, 0xc4068070,
++ 0x008ce800, 0x00000000,
++ 0x807d817d, 0x8070ff70,
++ 0x00000080, 0xbf0a7b7d,
++ 0xbfa2fff7, 0xbfa0016e,
++ 0xbef4007e, 0x8b75ff7f,
++ 0x0000ffff, 0x8c75ff75,
++ 0x00040000, 0xbef60080,
++ 0xbef700ff, 0x10807fac,
++ 0xbef1007f, 0xb8f20742,
++ 0x84729972, 0x8b6eff7f,
++ 0x04000000, 0xbfa1003b,
++ 0xbefe00c1, 0x857d9972,
++ 0x8b7d817d, 0xbf06817d,
++ 0xbfa20002, 0xbeff0080,
++ 0xbfa00001, 0xbeff00c1,
++ 0xb8ef4306, 0x8b6fc16f,
++ 0xbfa10030, 0x846f896f,
++ 0xbef6006f, 0xb8f83b05,
++ 0x80788178, 0xbf0d9972,
++ 0xbfa20002, 0x84788978,
++ 0xbfa00001, 0x84788a78,
++ 0xb8ee1e06, 0x846e8a6e,
++ 0x80786e78, 0x8078ff78,
++ 0x00000200, 0x8078ff78,
++ 0x00000080, 0xbef600ff,
++ 0x01000000, 0x857d9972,
++ 0x8b7d817d, 0xbf06817d,
++ 0xbefd0080, 0xbfa2000d,
++ 0xc4050078, 0x0080e800,
++ 0x00000000, 0xbf8a0000,
++ 0xdac00000, 0x00000000,
++ 0x807dff7d, 0x00000080,
++ 0x8078ff78, 0x00000080,
++ 0xbf0a6f7d, 0xbfa2fff4,
++ 0xbfa0000c, 0xc4050078,
++ 0x0080e800, 0x00000000,
++ 0xbf8a0000, 0xdac00000,
++ 0x00000000, 0x807dff7d,
++ 0x00000100, 0x8078ff78,
++ 0x00000100, 0xbf0a6f7d,
++ 0xbfa2fff4, 0xbef80080,
++ 0xbefe00c1, 0x857d9972,
++ 0x8b7d817d, 0xbf06817d,
++ 0xbfa20002, 0xbeff0080,
++ 0xbfa00001, 0xbeff00c1,
++ 0xb8ef3b05, 0x806f816f,
++ 0x846f826f, 0x857d9972,
++ 0x8b7d817d, 0xbf06817d,
++ 0xbfa2002c, 0xbef600ff,
++ 0x01000000, 0xbeee0078,
++ 0x8078ff78, 0x00000200,
++ 0xbefd0084, 0xbf0a6f7d,
++ 0xbfa10061, 0xc4050078,
++ 0x008ce800, 0x00000000,
++ 0xc4050078, 0x008ce801,
++ 0x00008000, 0xc4050078,
++ 0x008ce802, 0x00010000,
++ 0xc4050078, 0x008ce803,
++ 0x00018000, 0xbf8a0000,
++ 0x7e008500, 0x7e028501,
++ 0x7e048502, 0x7e068503,
++ 0x807d847d, 0x8078ff78,
++ 0x00000200, 0xbf0a6f7d,
++ 0xbfa2ffea, 0xc405006e,
++ 0x008ce800, 0x00000000,
++ 0xc405006e, 0x008ce801,
++ 0x00008000, 0xc405006e,
++ 0x008ce802, 0x00010000,
++ 0xc405006e, 0x008ce803,
++ 0x00018000, 0xbf8a0000,
++ 0xbfa0003d, 0xbef600ff,
++ 0x01000000, 0xbeee0078,
++ 0x8078ff78, 0x00000400,
++ 0xbefd0084, 0xbf0a6f7d,
++ 0xbfa10016, 0xc4050078,
++ 0x008ce800, 0x00000000,
++ 0xc4050078, 0x008ce801,
++ 0x00010000, 0xc4050078,
++ 0x008ce802, 0x00020000,
++ 0xc4050078, 0x008ce803,
++ 0x00030000, 0xbf8a0000,
++ 0x7e008500, 0x7e028501,
++ 0x7e048502, 0x7e068503,
++ 0x807d847d, 0x8078ff78,
++ 0x00000400, 0xbf0a6f7d,
++ 0xbfa2ffea, 0xb8ef1e06,
++ 0x8b6fc16f, 0xbfa1000f,
++ 0x846f836f, 0x806f7d6f,
++ 0xbefe00c1, 0xbeff0080,
++ 0xc4050078, 0x008ce800,
++ 0x00000000, 0xbf8a0000,
++ 0x7e008500, 0x807d817d,
++ 0x8078ff78, 0x00000080,
++ 0xbf0a6f7d, 0xbfa2fff6,
++ 0xbeff00c1, 0xc405006e,
++ 0x008ce800, 0x00000000,
++ 0xc405006e, 0x008ce801,
++ 0x00010000, 0xc405006e,
++ 0x008ce802, 0x00020000,
++ 0xc405006e, 0x008ce803,
++ 0x00030000, 0xbf8a0000,
+ 0xb8f83b05, 0x80788178,
+ 0xbf0d9972, 0xbfa20002,
+ 0x84788978, 0xbfa00001,
+ 0x84788a78, 0xb8ee1e06,
+ 0x846e8a6e, 0x80786e78,
+ 0x8078ff78, 0x00000200,
+- 0x8078ff78, 0x00000080,
+- 0xbef600ff, 0x01000000,
+- 0x857d9972, 0x8b7d817d,
+- 0xbf06817d, 0xbefd0080,
+- 0xbfa2000d, 0xc4050078,
+- 0x0080e800, 0x00000000,
+- 0xbf8a0000, 0xdac00000,
+- 0x00000000, 0x807dff7d,
+- 0x00000080, 0x8078ff78,
+- 0x00000080, 0xbf0a6f7d,
+- 0xbfa2fff4, 0xbfa0000c,
+- 0xc4050078, 0x0080e800,
+- 0x00000000, 0xbf8a0000,
+- 0xdac00000, 0x00000000,
+- 0x807dff7d, 0x00000100,
+- 0x8078ff78, 0x00000100,
+- 0xbf0a6f7d, 0xbfa2fff4,
+- 0xbef80080, 0xbefe00c1,
+- 0x857d9972, 0x8b7d817d,
+- 0xbf06817d, 0xbfa20002,
+- 0xbeff0080, 0xbfa00001,
+- 0xbeff00c1, 0xb8ef3b05,
+- 0x806f816f, 0x846f826f,
+- 0x857d9972, 0x8b7d817d,
+- 0xbf06817d, 0xbfa2002c,
++ 0x80f8ff78, 0x00000050,
+ 0xbef600ff, 0x01000000,
+- 0xbeee0078, 0x8078ff78,
+- 0x00000200, 0xbefd0084,
+- 0xbf0a6f7d, 0xbfa10061,
+- 0xc4050078, 0x008ce800,
+- 0x00000000, 0xc4050078,
+- 0x008ce801, 0x00008000,
+- 0xc4050078, 0x008ce802,
+- 0x00010000, 0xc4050078,
+- 0x008ce803, 0x00018000,
+- 0xbf8a0000, 0x7e008500,
+- 0x7e028501, 0x7e048502,
+- 0x7e068503, 0x807d847d,
++ 0xbefd00ff, 0x0000006c,
++ 0x80f89078, 0xf462403a,
++ 0xf0000000, 0xbf8a0000,
++ 0x80fd847d, 0xbf800000,
++ 0xbe804300, 0xbe824302,
++ 0x80f8a078, 0xf462603a,
++ 0xf0000000, 0xbf8a0000,
++ 0x80fd887d, 0xbf800000,
++ 0xbe804300, 0xbe824302,
++ 0xbe844304, 0xbe864306,
++ 0x80f8c078, 0xf462803a,
++ 0xf0000000, 0xbf8a0000,
++ 0x80fd907d, 0xbf800000,
++ 0xbe804300, 0xbe824302,
++ 0xbe844304, 0xbe864306,
++ 0xbe884308, 0xbe8a430a,
++ 0xbe8c430c, 0xbe8e430e,
++ 0xbf06807d, 0xbfa1fff0,
++ 0xb980f801, 0x00000000,
++ 0xb8f83b05, 0x80788178,
++ 0xbf0d9972, 0xbfa20002,
++ 0x84788978, 0xbfa00001,
++ 0x84788a78, 0xb8ee1e06,
++ 0x846e8a6e, 0x80786e78,
+ 0x8078ff78, 0x00000200,
+- 0xbf0a6f7d, 0xbfa2ffea,
+- 0xc405006e, 0x008ce800,
+- 0x00000000, 0xc405006e,
+- 0x008ce801, 0x00008000,
+- 0xc405006e, 0x008ce802,
+- 0x00010000, 0xc405006e,
+- 0x008ce803, 0x00018000,
+- 0xbf8a0000, 0xbfa0003d,
+ 0xbef600ff, 0x01000000,
+- 0xbeee0078, 0x8078ff78,
+- 0x00000400, 0xbefd0084,
+- 0xbf0a6f7d, 0xbfa10016,
+- 0xc4050078, 0x008ce800,
+- 0x00000000, 0xc4050078,
+- 0x008ce801, 0x00010000,
+- 0xc4050078, 0x008ce802,
+- 0x00020000, 0xc4050078,
+- 0x008ce803, 0x00030000,
+- 0xbf8a0000, 0x7e008500,
+- 0x7e028501, 0x7e048502,
+- 0x7e068503, 0x807d847d,
+- 0x8078ff78, 0x00000400,
+- 0xbf0a6f7d, 0xbfa2ffea,
+- 0xb8ef1e06, 0x8b6fc16f,
+- 0xbfa1000f, 0x846f836f,
+- 0x806f7d6f, 0xbefe00c1,
+- 0xbeff0080, 0xc4050078,
+- 0x008ce800, 0x00000000,
+- 0xbf8a0000, 0x7e008500,
+- 0x807d817d, 0x8078ff78,
+- 0x00000080, 0xbf0a6f7d,
+- 0xbfa2fff6, 0xbeff00c1,
+- 0xc405006e, 0x008ce800,
+- 0x00000000, 0xc405006e,
+- 0x008ce801, 0x00010000,
+- 0xc405006e, 0x008ce802,
+- 0x00020000, 0xc405006e,
+- 0x008ce803, 0x00030000,
+- 0xbf8a0000, 0xb8f83b05,
+- 0x80788178, 0xbf0d9972,
+- 0xbfa20002, 0x84788978,
+- 0xbfa00001, 0x84788a78,
+- 0xb8ee1e06, 0x846e8a6e,
+- 0x80786e78, 0x8078ff78,
+- 0x00000200, 0x80f8ff78,
+- 0x00000050, 0xbef600ff,
+- 0x01000000, 0xbefd00ff,
+- 0x0000006c, 0x80f89078,
+- 0xf462403a, 0xf0000000,
+- 0xbf8a0000, 0x80fd847d,
+- 0xbf800000, 0xbe804300,
+- 0xbe824302, 0x80f8a078,
+- 0xf462603a, 0xf0000000,
+- 0xbf8a0000, 0x80fd887d,
+- 0xbf800000, 0xbe804300,
+- 0xbe824302, 0xbe844304,
+- 0xbe864306, 0x80f8c078,
+- 0xf462803a, 0xf0000000,
+- 0xbf8a0000, 0x80fd907d,
+- 0xbf800000, 0xbe804300,
+- 0xbe824302, 0xbe844304,
+- 0xbe864306, 0xbe884308,
+- 0xbe8a430a, 0xbe8c430c,
+- 0xbe8e430e, 0xbf06807d,
+- 0xbfa1fff0, 0xb980f801,
+- 0x00000000, 0xb8f83b05,
+- 0x80788178, 0xbf0d9972,
+- 0xbfa20002, 0x84788978,
+- 0xbfa00001, 0x84788a78,
+- 0xb8ee1e06, 0x846e8a6e,
+- 0x80786e78, 0x8078ff78,
+- 0x00000200, 0xbef600ff,
+- 0x01000000, 0xbeff0071,
+- 0xf4621bfa, 0xf0000000,
+- 0x80788478, 0xf4621b3a,
++ 0xbeff0071, 0xf4621bfa,
+ 0xf0000000, 0x80788478,
+- 0xf4621b7a, 0xf0000000,
+- 0x80788478, 0xf4621c3a,
++ 0xf4621b3a, 0xf0000000,
++ 0x80788478, 0xf4621b7a,
+ 0xf0000000, 0x80788478,
+- 0xf4621c7a, 0xf0000000,
+- 0x80788478, 0xf4621eba,
++ 0xf4621c3a, 0xf0000000,
++ 0x80788478, 0xf4621c7a,
+ 0xf0000000, 0x80788478,
+- 0xf4621efa, 0xf0000000,
+- 0x80788478, 0xf4621e7a,
++ 0xf4621eba, 0xf0000000,
++ 0x80788478, 0xf4621efa,
+ 0xf0000000, 0x80788478,
+- 0xf4621cfa, 0xf0000000,
+- 0x80788478, 0xf4621bba,
++ 0xf4621e7a, 0xf0000000,
++ 0x80788478, 0xf4621cfa,
+ 0xf0000000, 0x80788478,
+- 0xbf8a0000, 0xb96ef814,
+ 0xf4621bba, 0xf0000000,
+ 0x80788478, 0xbf8a0000,
+- 0xb96ef815, 0xf4621bba,
++ 0xb96ef814, 0xf4621bba,
+ 0xf0000000, 0x80788478,
+- 0xbf8a0000, 0xb96ef812,
++ 0xbf8a0000, 0xb96ef815,
+ 0xf4621bba, 0xf0000000,
+ 0x80788478, 0xbf8a0000,
+- 0xb96ef813, 0x8b6eff7f,
+- 0x04000000, 0xbfa1000d,
+- 0x80788478, 0xf4621bba,
++ 0xb96ef812, 0xf4621bba,
+ 0xf0000000, 0x80788478,
+- 0xbf8a0000, 0xbf0d806e,
+- 0xbfa10006, 0x856e906e,
+- 0x8b6e6e6e, 0xbfa10003,
+- 0xbe804ec1, 0x816ec16e,
+- 0xbfa0fffb, 0xbefd006f,
+- 0xbefe0070, 0xbeff0071,
+- 0xb97b2011, 0x857b867b,
+- 0xb97b0191, 0x857b827b,
+- 0xb97bba11, 0xb973f801,
+- 0xb8ee3b05, 0x806e816e,
+- 0xbf0d9972, 0xbfa20002,
+- 0x846e896e, 0xbfa00001,
+- 0x846e8a6e, 0xb8ef1e06,
+- 0x846f8a6f, 0x806e6f6e,
+- 0x806eff6e, 0x00000200,
+- 0x806e746e, 0x826f8075,
+- 0x8b6fff6f, 0x0000ffff,
+- 0xf4605c37, 0xf8000050,
+- 0xf4605d37, 0xf8000060,
+- 0xf4601e77, 0xf8000074,
+- 0xbf8a0000, 0x8b6dff6d,
+- 0x0000ffff, 0x8bfe7e7e,
+- 0x8bea6a6a, 0xb97af804,
++ 0xbf8a0000, 0xb96ef813,
++ 0x8b6eff7f, 0x04000000,
++ 0xbfa1000d, 0x80788478,
++ 0xf4621bba, 0xf0000000,
++ 0x80788478, 0xbf8a0000,
++ 0xbf0d806e, 0xbfa10006,
++ 0x856e906e, 0x8b6e6e6e,
++ 0xbfa10003, 0xbe804ec1,
++ 0x816ec16e, 0xbfa0fffb,
++ 0xbefd006f, 0xbefe0070,
++ 0xbeff0071, 0xb97b2011,
++ 0x857b867b, 0xb97b0191,
++ 0x857b827b, 0xb97bba11,
++ 0xb973f801, 0xb8ee3b05,
++ 0x806e816e, 0xbf0d9972,
++ 0xbfa20002, 0x846e896e,
++ 0xbfa00001, 0x846e8a6e,
++ 0xb8ef1e06, 0x846f8a6f,
++ 0x806e6f6e, 0x806eff6e,
++ 0x00000200, 0x806e746e,
++ 0x826f8075, 0x8b6fff6f,
++ 0x0000ffff, 0xf4605c37,
++ 0xf8000050, 0xf4605d37,
++ 0xf8000060, 0xf4601e77,
++ 0xf8000074, 0xbf8a0000,
++ 0x8b6dff6d, 0x0000ffff,
++ 0x8bfe7e7e, 0x8bea6a6a,
++ 0xb97af804, 0xbe804ec2,
++ 0xbf94fffe, 0xbe804a6c,
+ 0xbe804ec2, 0xbf94fffe,
+- 0xbe804a6c, 0xbe804ec2,
+- 0xbf94fffe, 0xbfb10000,
++ 0xbfb10000, 0xbf9f0000,
+ 0xbf9f0000, 0xbf9f0000,
+ 0xbf9f0000, 0xbf9f0000,
+- 0xbf9f0000, 0x00000000,
+ };
+diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm
+index 7b9d36e5fa437..5a1a1b1f897fe 100644
+--- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm
++++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx12.asm
+@@ -30,6 +30,7 @@
+ #define CHIP_GFX12 37
+
+ #define SINGLE_STEP_MISSED_WORKAROUND 1 //workaround for lost TRAP_AFTER_INST exception when SAVECTX raised
++#define HAVE_VALU_SGPR_HAZARD (ASIC_FAMILY == CHIP_GFX12)
+
+ var SQ_WAVE_STATE_PRIV_BARRIER_COMPLETE_MASK = 0x4
+ var SQ_WAVE_STATE_PRIV_SCC_SHIFT = 9
+@@ -351,6 +352,7 @@ L_HAVE_VGPRS:
+ v_writelane_b32 v0, ttmp13, 0xD
+ v_writelane_b32 v0, exec_lo, 0xE
+ v_writelane_b32 v0, exec_hi, 0xF
++ valu_sgpr_hazard()
+
+ s_mov_b32 exec_lo, 0x3FFF
+ s_mov_b32 exec_hi, 0x0
+@@ -417,7 +419,6 @@ L_SAVE_HWREG:
+ v_mov_b32 v0, 0x0 //Offset[31:0] from buffer resource
+ v_mov_b32 v1, 0x0 //Offset[63:32] from buffer resource
+ v_mov_b32 v2, 0x0 //Set of SGPRs for TCP store
+- s_mov_b32 m0, 0x0 //Next lane of v2 to write to
+
+ // Ensure no further changes to barrier or LDS state.
+ // STATE_PRIV.BARRIER_COMPLETE may change up to this point.
+@@ -430,40 +431,41 @@ L_SAVE_HWREG:
+ s_andn2_b32 s_save_state_priv, s_save_state_priv, SQ_WAVE_STATE_PRIV_BARRIER_COMPLETE_MASK
+ s_or_b32 s_save_state_priv, s_save_state_priv, s_save_tmp
+
+- write_hwreg_to_v2(s_save_m0)
+- write_hwreg_to_v2(s_save_pc_lo)
+ s_andn2_b32 s_save_tmp, s_save_pc_hi, S_SAVE_PC_HI_FIRST_WAVE_MASK
+- write_hwreg_to_v2(s_save_tmp)
+- write_hwreg_to_v2(s_save_exec_lo)
+- write_hwreg_to_v2(s_save_exec_hi)
+- write_hwreg_to_v2(s_save_state_priv)
++ v_writelane_b32 v2, s_save_m0, 0x0
++ v_writelane_b32 v2, s_save_pc_lo, 0x1
++ v_writelane_b32 v2, s_save_tmp, 0x2
++ v_writelane_b32 v2, s_save_exec_lo, 0x3
++ v_writelane_b32 v2, s_save_exec_hi, 0x4
++ v_writelane_b32 v2, s_save_state_priv, 0x5
++ v_writelane_b32 v2, s_save_xnack_mask, 0x7
++ valu_sgpr_hazard()
+
+ s_getreg_b32 s_save_tmp, hwreg(HW_REG_WAVE_EXCP_FLAG_PRIV)
+- write_hwreg_to_v2(s_save_tmp)
++ v_writelane_b32 v2, s_save_tmp, 0x6
+
+- write_hwreg_to_v2(s_save_xnack_mask)
++ s_getreg_b32 s_save_tmp, hwreg(HW_REG_WAVE_MODE)
++ v_writelane_b32 v2, s_save_tmp, 0x8
+
+- s_getreg_b32 s_save_m0, hwreg(HW_REG_WAVE_MODE)
+- write_hwreg_to_v2(s_save_m0)
++ s_getreg_b32 s_save_tmp, hwreg(HW_REG_WAVE_SCRATCH_BASE_LO)
++ v_writelane_b32 v2, s_save_tmp, 0x9
+
+- s_getreg_b32 s_save_m0, hwreg(HW_REG_WAVE_SCRATCH_BASE_LO)
+- write_hwreg_to_v2(s_save_m0)
++ s_getreg_b32 s_save_tmp, hwreg(HW_REG_WAVE_SCRATCH_BASE_HI)
++ v_writelane_b32 v2, s_save_tmp, 0xA
+
+- s_getreg_b32 s_save_m0, hwreg(HW_REG_WAVE_SCRATCH_BASE_HI)
+- write_hwreg_to_v2(s_save_m0)
++ s_getreg_b32 s_save_tmp, hwreg(HW_REG_WAVE_EXCP_FLAG_USER)
++ v_writelane_b32 v2, s_save_tmp, 0xB
+
+- s_getreg_b32 s_save_m0, hwreg(HW_REG_WAVE_EXCP_FLAG_USER)
+- write_hwreg_to_v2(s_save_m0)
+-
+- s_getreg_b32 s_save_m0, hwreg(HW_REG_WAVE_TRAP_CTRL)
+- write_hwreg_to_v2(s_save_m0)
++ s_getreg_b32 s_save_tmp, hwreg(HW_REG_WAVE_TRAP_CTRL)
++ v_writelane_b32 v2, s_save_tmp, 0xC
+
+ s_getreg_b32 s_save_tmp, hwreg(HW_REG_WAVE_STATUS)
+- write_hwreg_to_v2(s_save_tmp)
++ v_writelane_b32 v2, s_save_tmp, 0xD
+
+ s_get_barrier_state s_save_tmp, -1
+ s_wait_kmcnt (0)
+- write_hwreg_to_v2(s_save_tmp)
++ v_writelane_b32 v2, s_save_tmp, 0xE
++ valu_sgpr_hazard()
+
+ // Write HWREGs with 16 VGPR lanes. TTMPs occupy space after this.
+ s_mov_b32 exec_lo, 0xFFFF
+@@ -497,10 +499,12 @@ L_SAVE_SGPR_LOOP:
+ s_movrels_b64 s12, s12 //s12 = s[12+m0], s13 = s[13+m0]
+ s_movrels_b64 s14, s14 //s14 = s[14+m0], s15 = s[15+m0]
+
+- write_16sgpr_to_v2(s0)
+-
+- s_cmp_eq_u32 ttmp13, 0x20 //have 32 VGPR lanes filled?
+- s_cbranch_scc0 L_SAVE_SGPR_SKIP_TCP_STORE
++ s_cmp_eq_u32 ttmp13, 0x0
++ s_cbranch_scc0 L_WRITE_V2_SECOND_HALF
++ write_16sgpr_to_v2(s0, 0x0)
++ s_branch L_SAVE_SGPR_SKIP_TCP_STORE
++L_WRITE_V2_SECOND_HALF:
++ write_16sgpr_to_v2(s0, 0x10)
+
+ buffer_store_dword v2, v0, s_save_buf_rsrc0, s_save_mem_offset scope:SCOPE_SYS
+ s_add_u32 s_save_mem_offset, s_save_mem_offset, 0x80
+@@ -1056,27 +1060,21 @@ L_END_PGM:
+ s_endpgm_saved
+ end
+
+-function write_hwreg_to_v2(s)
+- // Copy into VGPR for later TCP store.
+- v_writelane_b32 v2, s, m0
+- s_add_u32 m0, m0, 0x1
+-end
+-
+-
+-function write_16sgpr_to_v2(s)
++function write_16sgpr_to_v2(s, lane_offset)
+ // Copy into VGPR for later TCP store.
+ for var sgpr_idx = 0; sgpr_idx < 16; sgpr_idx ++
+- v_writelane_b32 v2, s[sgpr_idx], ttmp13
+- s_add_u32 ttmp13, ttmp13, 0x1
++ v_writelane_b32 v2, s[sgpr_idx], sgpr_idx + lane_offset
+ end
++ valu_sgpr_hazard()
++ s_add_u32 ttmp13, ttmp13, 0x10
+ end
+
+ function write_12sgpr_to_v2(s)
+ // Copy into VGPR for later TCP store.
+ for var sgpr_idx = 0; sgpr_idx < 12; sgpr_idx ++
+- v_writelane_b32 v2, s[sgpr_idx], ttmp13
+- s_add_u32 ttmp13, ttmp13, 0x1
++ v_writelane_b32 v2, s[sgpr_idx], sgpr_idx
+ end
++ valu_sgpr_hazard()
+ end
+
+ function read_hwreg_from_mem(s, s_rsrc, s_mem_offset)
+@@ -1128,3 +1126,11 @@ function get_wave_size2(s_reg)
+ s_getreg_b32 s_reg, hwreg(HW_REG_WAVE_STATUS,SQ_WAVE_STATUS_WAVE64_SHIFT,SQ_WAVE_STATUS_WAVE64_SIZE)
+ s_lshl_b32 s_reg, s_reg, S_WAVE_SIZE
+ end
++
++function valu_sgpr_hazard
++#if HAVE_VALU_SGPR_HAZARD
++ for var rep = 0; rep < 8; rep ++
++ ds_nop
++ end
++#endif
++end
+--
+2.39.5
+
diff --git a/queue-6.12/drm-amdkfd-remove-gfx-12-trap-handler-page-size-cap.patch b/queue-6.12/drm-amdkfd-remove-gfx-12-trap-handler-page-size-cap.patch
new file mode 100644
index 0000000000..563c466e1f
--- /dev/null
+++ b/queue-6.12/drm-amdkfd-remove-gfx-12-trap-handler-page-size-cap.patch
@@ -0,0 +1,37 @@
+From e8c3565abdfa7dc2b5161ce7fb4e1c1b2abd5844 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Nov 2024 12:38:30 -0500
+Subject: drm/amdkfd: remove gfx 12 trap handler page size cap
+
+From: Jonathan Kim <jonathan.kim@amd.com>
+
+[ Upstream commit cd82f29ec51b2e616289db7b258a936127c16efa ]
+
+GFX 12 does not require a page size cap for the trap handler because
+it does not require a CWSR work around like GFX 11 did.
+
+Signed-off-by: Jonathan Kim <jonathan.kim@amd.com>
+Reviewed-by: David Belanger <david.belanger@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_device.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+index 9186ef0bd2a32..07eadab4c1c4d 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+@@ -537,7 +537,8 @@ static void kfd_cwsr_init(struct kfd_dev *kfd)
+ kfd->cwsr_isa = cwsr_trap_gfx11_hex;
+ kfd->cwsr_isa_size = sizeof(cwsr_trap_gfx11_hex);
+ } else {
+- BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_hex) > PAGE_SIZE);
++ BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_hex)
++ > KFD_CWSR_TMA_OFFSET);
+ kfd->cwsr_isa = cwsr_trap_gfx12_hex;
+ kfd->cwsr_isa_size = sizeof(cwsr_trap_gfx12_hex);
+ }
+--
+2.39.5
+
diff --git a/queue-6.12/drm-fbdev-dma-add-shadow-buffering-for-deferred-i-o.patch b/queue-6.12/drm-fbdev-dma-add-shadow-buffering-for-deferred-i-o.patch
new file mode 100644
index 0000000000..ce3396e163
--- /dev/null
+++ b/queue-6.12/drm-fbdev-dma-add-shadow-buffering-for-deferred-i-o.patch
@@ -0,0 +1,347 @@
+From 516707b69d16dc07cfa3f1aaf48e5da31b9949b4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Dec 2024 10:06:28 +0100
+Subject: drm/fbdev-dma: Add shadow buffering for deferred I/O
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+[ Upstream commit 3603996432997f7c88da37a97062a46cda01ac9d ]
+
+DMA areas are not necessarily backed by struct page, so we cannot
+rely on it for deferred I/O. Allocate a shadow buffer for drivers
+that require deferred I/O and use it as framebuffer memory.
+
+Fixes driver errors about being "Unable to handle kernel NULL pointer
+dereference at virtual address" or "Unable to handle kernel paging
+request at virtual address".
+
+The patch splits drm_fbdev_dma_driver_fbdev_probe() in an initial
+allocation, which creates the DMA-backed buffer object, and a tail
+that sets up the fbdev data structures. There is a tail function for
+direct memory mappings and a tail function for deferred I/O with
+the shadow buffer.
+
+It is no longer possible to use deferred I/O without shadow buffer.
+It can be re-added if there exists a reliably test for usable struct
+page in the allocated DMA-backed buffer object.
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Reported-by: Nuno Gonçalves <nunojpg@gmail.com>
+CLoses: https://lore.kernel.org/dri-devel/CAEXMXLR55DziAMbv_+2hmLeH-jP96pmit6nhs6siB22cpQFr9w@mail.gmail.com/
+Tested-by: Nuno Gonçalves <nunojpg@gmail.com>
+Fixes: 5ab91447aa13 ("drm/tiny/ili9225: Use fbdev-dma")
+Cc: Thomas Zimmermann <tzimmermann@suse.de>
+Cc: <stable@vger.kernel.org> # v6.11+
+Reviewed-by: Simona Vetter <simona.vetter@ffwll.ch>
+Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20241211090643.74250-1-tzimmermann@suse.de
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/drm_fbdev_dma.c | 219 +++++++++++++++++++++++---------
+ 1 file changed, 156 insertions(+), 63 deletions(-)
+
+diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
+index 7c8287c18e381..6fcf2a8bf6762 100644
+--- a/drivers/gpu/drm/drm_fbdev_dma.c
++++ b/drivers/gpu/drm/drm_fbdev_dma.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: MIT
+
+ #include <linux/fb.h>
++#include <linux/vmalloc.h>
+
+ #include <drm/drm_crtc_helper.h>
+ #include <drm/drm_drv.h>
+@@ -72,43 +73,108 @@ static const struct fb_ops drm_fbdev_dma_fb_ops = {
+ .fb_destroy = drm_fbdev_dma_fb_destroy,
+ };
+
+-FB_GEN_DEFAULT_DEFERRED_DMAMEM_OPS(drm_fbdev_dma,
++FB_GEN_DEFAULT_DEFERRED_DMAMEM_OPS(drm_fbdev_dma_shadowed,
+ drm_fb_helper_damage_range,
+ drm_fb_helper_damage_area);
+
+-static int drm_fbdev_dma_deferred_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
++static void drm_fbdev_dma_shadowed_fb_destroy(struct fb_info *info)
+ {
+ struct drm_fb_helper *fb_helper = info->par;
+- struct drm_framebuffer *fb = fb_helper->fb;
+- struct drm_gem_dma_object *dma = drm_fb_dma_get_gem_obj(fb, 0);
++ void *shadow = info->screen_buffer;
++
++ if (!fb_helper->dev)
++ return;
+
+- if (!dma->map_noncoherent)
+- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
++ if (info->fbdefio)
++ fb_deferred_io_cleanup(info);
++ drm_fb_helper_fini(fb_helper);
++ vfree(shadow);
+
+- return fb_deferred_io_mmap(info, vma);
++ drm_client_buffer_vunmap(fb_helper->buffer);
++ drm_client_framebuffer_delete(fb_helper->buffer);
++ drm_client_release(&fb_helper->client);
++ drm_fb_helper_unprepare(fb_helper);
++ kfree(fb_helper);
+ }
+
+-static const struct fb_ops drm_fbdev_dma_deferred_fb_ops = {
++static const struct fb_ops drm_fbdev_dma_shadowed_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = drm_fbdev_dma_fb_open,
+ .fb_release = drm_fbdev_dma_fb_release,
+- __FB_DEFAULT_DEFERRED_OPS_RDWR(drm_fbdev_dma),
++ FB_DEFAULT_DEFERRED_OPS(drm_fbdev_dma_shadowed),
+ DRM_FB_HELPER_DEFAULT_OPS,
+- __FB_DEFAULT_DEFERRED_OPS_DRAW(drm_fbdev_dma),
+- .fb_mmap = drm_fbdev_dma_deferred_fb_mmap,
+- .fb_destroy = drm_fbdev_dma_fb_destroy,
++ .fb_destroy = drm_fbdev_dma_shadowed_fb_destroy,
+ };
+
+ /*
+ * struct drm_fb_helper
+ */
+
++static void drm_fbdev_dma_damage_blit_real(struct drm_fb_helper *fb_helper,
++ struct drm_clip_rect *clip,
++ struct iosys_map *dst)
++{
++ struct drm_framebuffer *fb = fb_helper->fb;
++ size_t offset = clip->y1 * fb->pitches[0];
++ size_t len = clip->x2 - clip->x1;
++ unsigned int y;
++ void *src;
++
++ switch (drm_format_info_bpp(fb->format, 0)) {
++ case 1:
++ offset += clip->x1 / 8;
++ len = DIV_ROUND_UP(len + clip->x1 % 8, 8);
++ break;
++ case 2:
++ offset += clip->x1 / 4;
++ len = DIV_ROUND_UP(len + clip->x1 % 4, 4);
++ break;
++ case 4:
++ offset += clip->x1 / 2;
++ len = DIV_ROUND_UP(len + clip->x1 % 2, 2);
++ break;
++ default:
++ offset += clip->x1 * fb->format->cpp[0];
++ len *= fb->format->cpp[0];
++ break;
++ }
++
++ src = fb_helper->info->screen_buffer + offset;
++ iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
++
++ for (y = clip->y1; y < clip->y2; y++) {
++ iosys_map_memcpy_to(dst, 0, src, len);
++ iosys_map_incr(dst, fb->pitches[0]);
++ src += fb->pitches[0];
++ }
++}
++
++static int drm_fbdev_dma_damage_blit(struct drm_fb_helper *fb_helper,
++ struct drm_clip_rect *clip)
++{
++ struct drm_client_buffer *buffer = fb_helper->buffer;
++ struct iosys_map dst;
++
++ /*
++ * For fbdev emulation, we only have to protect against fbdev modeset
++ * operations. Nothing else will involve the client buffer's BO. So it
++ * is sufficient to acquire struct drm_fb_helper.lock here.
++ */
++ mutex_lock(&fb_helper->lock);
++
++ dst = buffer->map;
++ drm_fbdev_dma_damage_blit_real(fb_helper, clip, &dst);
++
++ mutex_unlock(&fb_helper->lock);
++
++ return 0;
++}
++
+ static int drm_fbdev_dma_helper_fb_probe(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+ {
+ return drm_fbdev_dma_driver_fbdev_probe(fb_helper, sizes);
+ }
+-
+ static int drm_fbdev_dma_helper_fb_dirty(struct drm_fb_helper *helper,
+ struct drm_clip_rect *clip)
+ {
+@@ -120,6 +186,10 @@ static int drm_fbdev_dma_helper_fb_dirty(struct drm_fb_helper *helper,
+ return 0;
+
+ if (helper->fb->funcs->dirty) {
++ ret = drm_fbdev_dma_damage_blit(helper, clip);
++ if (drm_WARN_ONCE(dev, ret, "Damage blitter failed: ret=%d\n", ret))
++ return ret;
++
+ ret = helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1);
+ if (drm_WARN_ONCE(dev, ret, "Dirty helper failed: ret=%d\n", ret))
+ return ret;
+@@ -137,14 +207,80 @@ static const struct drm_fb_helper_funcs drm_fbdev_dma_helper_funcs = {
+ * struct drm_fb_helper
+ */
+
++static int drm_fbdev_dma_driver_fbdev_probe_tail(struct drm_fb_helper *fb_helper,
++ struct drm_fb_helper_surface_size *sizes)
++{
++ struct drm_device *dev = fb_helper->dev;
++ struct drm_client_buffer *buffer = fb_helper->buffer;
++ struct drm_gem_dma_object *dma_obj = to_drm_gem_dma_obj(buffer->gem);
++ struct drm_framebuffer *fb = fb_helper->fb;
++ struct fb_info *info = fb_helper->info;
++ struct iosys_map map = buffer->map;
++
++ info->fbops = &drm_fbdev_dma_fb_ops;
++
++ /* screen */
++ info->flags |= FBINFO_VIRTFB; /* system memory */
++ if (dma_obj->map_noncoherent)
++ info->flags |= FBINFO_READS_FAST; /* signal caching */
++ info->screen_size = sizes->surface_height * fb->pitches[0];
++ info->screen_buffer = map.vaddr;
++ if (!(info->flags & FBINFO_HIDE_SMEM_START)) {
++ if (!drm_WARN_ON(dev, is_vmalloc_addr(info->screen_buffer)))
++ info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer));
++ }
++ info->fix.smem_len = info->screen_size;
++
++ return 0;
++}
++
++static int drm_fbdev_dma_driver_fbdev_probe_tail_shadowed(struct drm_fb_helper *fb_helper,
++ struct drm_fb_helper_surface_size *sizes)
++{
++ struct drm_client_buffer *buffer = fb_helper->buffer;
++ struct fb_info *info = fb_helper->info;
++ size_t screen_size = buffer->gem->size;
++ void *screen_buffer;
++ int ret;
++
++ /*
++ * Deferred I/O requires struct page for framebuffer memory,
++ * which is not guaranteed for all DMA ranges. We thus create
++ * a shadow buffer in system memory.
++ */
++ screen_buffer = vzalloc(screen_size);
++ if (!screen_buffer)
++ return -ENOMEM;
++
++ info->fbops = &drm_fbdev_dma_shadowed_fb_ops;
++
++ /* screen */
++ info->flags |= FBINFO_VIRTFB; /* system memory */
++ info->flags |= FBINFO_READS_FAST; /* signal caching */
++ info->screen_buffer = screen_buffer;
++ info->fix.smem_len = screen_size;
++
++ fb_helper->fbdefio.delay = HZ / 20;
++ fb_helper->fbdefio.deferred_io = drm_fb_helper_deferred_io;
++
++ info->fbdefio = &fb_helper->fbdefio;
++ ret = fb_deferred_io_init(info);
++ if (ret)
++ goto err_vfree;
++
++ return 0;
++
++err_vfree:
++ vfree(screen_buffer);
++ return ret;
++}
++
+ int drm_fbdev_dma_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+ {
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_device *dev = fb_helper->dev;
+- bool use_deferred_io = false;
+ struct drm_client_buffer *buffer;
+- struct drm_gem_dma_object *dma_obj;
+ struct drm_framebuffer *fb;
+ struct fb_info *info;
+ u32 format;
+@@ -161,19 +297,9 @@ int drm_fbdev_dma_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
+ sizes->surface_height, format);
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+- dma_obj = to_drm_gem_dma_obj(buffer->gem);
+
+ fb = buffer->fb;
+
+- /*
+- * Deferred I/O requires struct page for framebuffer memory,
+- * which is not guaranteed for all DMA ranges. We thus only
+- * install deferred I/O if we have a framebuffer that requires
+- * it.
+- */
+- if (fb->funcs->dirty)
+- use_deferred_io = true;
+-
+ ret = drm_client_buffer_vmap(buffer, &map);
+ if (ret) {
+ goto err_drm_client_buffer_delete;
+@@ -194,45 +320,12 @@ int drm_fbdev_dma_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
+
+ drm_fb_helper_fill_info(info, fb_helper, sizes);
+
+- if (use_deferred_io)
+- info->fbops = &drm_fbdev_dma_deferred_fb_ops;
++ if (fb->funcs->dirty)
++ ret = drm_fbdev_dma_driver_fbdev_probe_tail_shadowed(fb_helper, sizes);
+ else
+- info->fbops = &drm_fbdev_dma_fb_ops;
+-
+- /* screen */
+- info->flags |= FBINFO_VIRTFB; /* system memory */
+- if (dma_obj->map_noncoherent)
+- info->flags |= FBINFO_READS_FAST; /* signal caching */
+- info->screen_size = sizes->surface_height * fb->pitches[0];
+- info->screen_buffer = map.vaddr;
+- if (!(info->flags & FBINFO_HIDE_SMEM_START)) {
+- if (!drm_WARN_ON(dev, is_vmalloc_addr(info->screen_buffer)))
+- info->fix.smem_start = page_to_phys(virt_to_page(info->screen_buffer));
+- }
+- info->fix.smem_len = info->screen_size;
+-
+- /*
+- * Only set up deferred I/O if the screen buffer supports
+- * it. If this disagrees with the previous test for ->dirty,
+- * mmap on the /dev/fb file might not work correctly.
+- */
+- if (!is_vmalloc_addr(info->screen_buffer) && info->fix.smem_start) {
+- unsigned long pfn = info->fix.smem_start >> PAGE_SHIFT;
+-
+- if (drm_WARN_ON(dev, !pfn_to_page(pfn)))
+- use_deferred_io = false;
+- }
+-
+- /* deferred I/O */
+- if (use_deferred_io) {
+- fb_helper->fbdefio.delay = HZ / 20;
+- fb_helper->fbdefio.deferred_io = drm_fb_helper_deferred_io;
+-
+- info->fbdefio = &fb_helper->fbdefio;
+- ret = fb_deferred_io_init(info);
+- if (ret)
+- goto err_drm_fb_helper_release_info;
+- }
++ ret = drm_fbdev_dma_driver_fbdev_probe_tail(fb_helper, sizes);
++ if (ret)
++ goto err_drm_fb_helper_release_info;
+
+ return 0;
+
+--
+2.39.5
+
diff --git a/queue-6.12/drm-msm-dp-account-for-widebus-and-yuv420-during-mod.patch b/queue-6.12/drm-msm-dp-account-for-widebus-and-yuv420-during-mod.patch
new file mode 100644
index 0000000000..9537b57b4a
--- /dev/null
+++ b/queue-6.12/drm-msm-dp-account-for-widebus-and-yuv420-during-mod.patch
@@ -0,0 +1,75 @@
+From d1829f86087e1f01617eb0b7d4f6e5fd72b62e41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Jul 2025 17:47:38 -0400
+Subject: drm/msm/dp: account for widebus and yuv420 during mode validation
+
+[ Upstream commit df9cf852ca3099feb8fed781bdd5d3863af001c8 ]
+
+Widebus allows the DP controller to operate in 2 pixel per clock mode.
+The mode validation logic validates the mode->clock against the max
+DP pixel clock. However the max DP pixel clock limit assumes widebus
+is already enabled. Adjust the mode validation logic to only compare
+the adjusted pixel clock which accounts for widebus against the max DP
+pixel clock. Also fix the mode validation logic for YUV420 modes as in
+that case as well, only half the pixel clock is needed.
+
+Cc: stable@vger.kernel.org
+Fixes: 757a2f36ab09 ("drm/msm/dp: enable widebus feature for display port")
+Fixes: 6db6e5606576 ("drm/msm/dp: change clock related programming for YUV420 over DP")
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Tested-by: Dale Whinham <daleyo@gmail.com>
+Patchwork: https://patchwork.freedesktop.org/patch/635789/
+Link: https://lore.kernel.org/r/20250206-dp-widebus-fix-v2-1-cb89a0313286@quicinc.com
+Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/dp/dp_display.c | 11 ++++++-----
+ drivers/gpu/drm/msm/dp/dp_drm.c | 5 ++++-
+ 2 files changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
+index e1228fb093ee0..a5c1534eafdb1 100644
+--- a/drivers/gpu/drm/msm/dp/dp_display.c
++++ b/drivers/gpu/drm/msm/dp/dp_display.c
+@@ -928,16 +928,17 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
+ return -EINVAL;
+ }
+
+- if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+- return MODE_CLOCK_HIGH;
+-
+ dp_display = container_of(dp, struct dp_display_private, dp_display);
+ link_info = &dp_display->panel->link_info;
+
+- if (drm_mode_is_420_only(&dp->connector->display_info, mode) &&
+- dp_display->panel->vsc_sdp_supported)
++ if ((drm_mode_is_420_only(&dp->connector->display_info, mode) &&
++ dp_display->panel->vsc_sdp_supported) ||
++ msm_dp_wide_bus_available(dp))
+ mode_pclk_khz /= 2;
+
++ if (mode_pclk_khz > DP_MAX_PIXEL_CLK_KHZ)
++ return MODE_CLOCK_HIGH;
++
+ mode_bpp = dp->connector->display_info.bpc * num_components;
+ if (!mode_bpp)
+ mode_bpp = default_bpp;
+diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
+index 1b9be5bd97f12..da0176eae3fe3 100644
+--- a/drivers/gpu/drm/msm/dp/dp_drm.c
++++ b/drivers/gpu/drm/msm/dp/dp_drm.c
+@@ -257,7 +257,10 @@ static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge,
+ return -EINVAL;
+ }
+
+- if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
++ if (msm_dp_wide_bus_available(dp))
++ mode_pclk_khz /= 2;
++
++ if (mode_pclk_khz > DP_MAX_PIXEL_CLK_KHZ)
+ return MODE_CLOCK_HIGH;
+
+ /*
+--
+2.39.5
+
diff --git a/queue-6.12/drm-xe-carve-out-wopcm-portion-from-the-stolen-memor.patch b/queue-6.12/drm-xe-carve-out-wopcm-portion-from-the-stolen-memor.patch
new file mode 100644
index 0000000000..f96c40e744
--- /dev/null
+++ b/queue-6.12/drm-xe-carve-out-wopcm-portion-from-the-stolen-memor.patch
@@ -0,0 +1,120 @@
+From 1560183dd074b967cddf6c175dbdc81cd9d08031 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Jul 2025 17:33:25 -0400
+Subject: drm/xe: Carve out wopcm portion from the stolen memory
+
+[ Upstream commit e977499820782ab1c69f354d9f41b6d9ad1f43d9 ]
+
+The top of stolen memory is WOPCM, which shouldn't be accessed. Remove
+this portion from the stolen memory region for discrete platforms.
+This was already done for integrated, but was missing for discrete
+platforms.
+
+This also moves get_wopcm_size() so detect_bar2_dgfx() and
+detect_bar2_integrated can use the same function.
+
+v2: Improve commit message and suitable stable version tag(Lucas)
+
+Fixes: d8b52a02cb40 ("drm/xe: Implement stolen memory.")
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Matthew Auld <matthew.auld@intel.com>
+Cc: Lucas De Marchi <lucas.demarchi@intel.com>
+Cc: stable@vger.kernel.org # v6.11+
+Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20250210143654.2076747-1-nirmoy.das@intel.com
+Signed-off-by: Nirmoy Das <nirmoy.das@intel.com>
+(cherry picked from commit 2c7f45cc7e197a792ce5c693e56ea48f60b312da)
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c | 54 ++++++++++++++------------
+ 1 file changed, 30 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c
+index ef84fa757b26f..34e38bb167bac 100644
+--- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c
++++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c
+@@ -57,12 +57,35 @@ bool xe_ttm_stolen_cpu_access_needs_ggtt(struct xe_device *xe)
+ return GRAPHICS_VERx100(xe) < 1270 && !IS_DGFX(xe);
+ }
+
++static u32 get_wopcm_size(struct xe_device *xe)
++{
++ u32 wopcm_size;
++ u64 val;
++
++ val = xe_mmio_read64_2x32(xe_root_mmio_gt(xe), STOLEN_RESERVED);
++ val = REG_FIELD_GET64(WOPCM_SIZE_MASK, val);
++
++ switch (val) {
++ case 0x5 ... 0x6:
++ val--;
++ fallthrough;
++ case 0x0 ... 0x3:
++ wopcm_size = (1U << val) * SZ_1M;
++ break;
++ default:
++ WARN(1, "Missing case wopcm_size=%llx\n", val);
++ wopcm_size = 0;
++ }
++
++ return wopcm_size;
++}
++
+ static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
+ {
+ struct xe_tile *tile = xe_device_get_root_tile(xe);
+ struct xe_gt *mmio = xe_root_mmio_gt(xe);
+ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
+- u64 stolen_size;
++ u64 stolen_size, wopcm_size;
+ u64 tile_offset;
+ u64 tile_size;
+
+@@ -74,7 +97,13 @@ static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
+ if (drm_WARN_ON(&xe->drm, tile_size < mgr->stolen_base))
+ return 0;
+
++ /* Carve out the top of DSM as it contains the reserved WOPCM region */
++ wopcm_size = get_wopcm_size(xe);
++ if (drm_WARN_ON(&xe->drm, !wopcm_size))
++ return 0;
++
+ stolen_size = tile_size - mgr->stolen_base;
++ stolen_size -= wopcm_size;
+
+ /* Verify usage fits in the actual resource available */
+ if (mgr->stolen_base + stolen_size <= pci_resource_len(pdev, LMEM_BAR))
+@@ -89,29 +118,6 @@ static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
+ return ALIGN_DOWN(stolen_size, SZ_1M);
+ }
+
+-static u32 get_wopcm_size(struct xe_device *xe)
+-{
+- u32 wopcm_size;
+- u64 val;
+-
+- val = xe_mmio_read64_2x32(xe_root_mmio_gt(xe), STOLEN_RESERVED);
+- val = REG_FIELD_GET64(WOPCM_SIZE_MASK, val);
+-
+- switch (val) {
+- case 0x5 ... 0x6:
+- val--;
+- fallthrough;
+- case 0x0 ... 0x3:
+- wopcm_size = (1U << val) * SZ_1M;
+- break;
+- default:
+- WARN(1, "Missing case wopcm_size=%llx\n", val);
+- wopcm_size = 0;
+- }
+-
+- return wopcm_size;
+-}
+-
+ static u32 detect_bar2_integrated(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr)
+ {
+ struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
+--
+2.39.5
+
diff --git a/queue-6.12/iio-dac-ad3552r-changes-to-use-field_prep.patch b/queue-6.12/iio-dac-ad3552r-changes-to-use-field_prep.patch
new file mode 100644
index 0000000000..5381763973
--- /dev/null
+++ b/queue-6.12/iio-dac-ad3552r-changes-to-use-field_prep.patch
@@ -0,0 +1,310 @@
+From 5ac841dad37a42948a41cbddd6ee789fb30adf70 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Oct 2024 22:45:32 +0100
+Subject: iio: dac: ad3552r: changes to use FIELD_PREP
+
+From: Angelo Dureghello <adureghello@baylibre.com>
+
+[ Upstream commit d5ac6cb1c8f3e14d93e2a50d9357a8acdbc5c166 ]
+
+Changes to use FIELD_PREP, so that driver-specific ad3552r_field_prep
+is removed. Variables (arrays) that was used to call ad3552r_field_prep
+are removed too.
+
+Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
+Reviewed-by: David Lechner <dlechner@baylibre.com>
+Link: https://patch.msgid.link/20241028-wip-bl-ad3552r-axi-v0-iio-testing-v9-5-f6960b4f9719@kernel-space.org
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/dac/ad3552r.c | 167 ++++++++++++--------------------------
+ 1 file changed, 50 insertions(+), 117 deletions(-)
+
+diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
+index 390d3fab21478..aa453d3de5e1c 100644
+--- a/drivers/iio/dac/ad3552r.c
++++ b/drivers/iio/dac/ad3552r.c
+@@ -6,6 +6,7 @@
+ * Copyright 2021 Analog Devices Inc.
+ */
+ #include <linux/unaligned.h>
++#include <linux/bitfield.h>
+ #include <linux/device.h>
+ #include <linux/iio/triggered_buffer.h>
+ #include <linux/iio/trigger_consumer.h>
+@@ -210,46 +211,6 @@ static const s32 gains_scaling_table[] = {
+ [AD3552R_CH_GAIN_SCALING_0_125] = 125
+ };
+
+-enum ad3552r_dev_attributes {
+- /* - Direct register values */
+- /* From 0-3 */
+- AD3552R_SDO_DRIVE_STRENGTH,
+- /*
+- * 0 -> Internal Vref, vref_io pin floating (default)
+- * 1 -> Internal Vref, vref_io driven by internal vref
+- * 2 or 3 -> External Vref
+- */
+- AD3552R_VREF_SELECT,
+- /* Read registers in ascending order if set. Else descending */
+- AD3552R_ADDR_ASCENSION,
+-};
+-
+-enum ad3552r_ch_attributes {
+- /* DAC powerdown */
+- AD3552R_CH_DAC_POWERDOWN,
+- /* DAC amplifier powerdown */
+- AD3552R_CH_AMPLIFIER_POWERDOWN,
+- /* Select the output range. Select from enum ad3552r_ch_output_range */
+- AD3552R_CH_OUTPUT_RANGE_SEL,
+- /*
+- * Over-rider the range selector in order to manually set the output
+- * voltage range
+- */
+- AD3552R_CH_RANGE_OVERRIDE,
+- /* Manually set the offset voltage */
+- AD3552R_CH_GAIN_OFFSET,
+- /* Sets the polarity of the offset. */
+- AD3552R_CH_GAIN_OFFSET_POLARITY,
+- /* PDAC gain scaling */
+- AD3552R_CH_GAIN_SCALING_P,
+- /* NDAC gain scaling */
+- AD3552R_CH_GAIN_SCALING_N,
+- /* Rfb value */
+- AD3552R_CH_RFB,
+- /* Channel select. When set allow Input -> DAC and Mask -> DAC */
+- AD3552R_CH_SELECT,
+-};
+-
+ struct ad3552r_ch_data {
+ s32 scale_int;
+ s32 scale_dec;
+@@ -285,45 +246,6 @@ struct ad3552r_desc {
+ unsigned int num_ch;
+ };
+
+-static const u16 addr_mask_map[][2] = {
+- [AD3552R_ADDR_ASCENSION] = {
+- AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
+- AD3552R_MASK_ADDR_ASCENSION
+- },
+- [AD3552R_SDO_DRIVE_STRENGTH] = {
+- AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+- AD3552R_MASK_SDO_DRIVE_STRENGTH
+- },
+- [AD3552R_VREF_SELECT] = {
+- AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+- AD3552R_MASK_REFERENCE_VOLTAGE_SEL
+- },
+-};
+-
+-/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */
+-static const u16 addr_mask_map_ch[][3] = {
+- [AD3552R_CH_DAC_POWERDOWN] = {
+- AD3552R_REG_ADDR_POWERDOWN_CONFIG,
+- AD3552R_MASK_CH_DAC_POWERDOWN(0),
+- AD3552R_MASK_CH_DAC_POWERDOWN(1)
+- },
+- [AD3552R_CH_AMPLIFIER_POWERDOWN] = {
+- AD3552R_REG_ADDR_POWERDOWN_CONFIG,
+- AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0),
+- AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1)
+- },
+- [AD3552R_CH_OUTPUT_RANGE_SEL] = {
+- AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
+- AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0),
+- AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1)
+- },
+- [AD3552R_CH_SELECT] = {
+- AD3552R_REG_ADDR_CH_SELECT_16B,
+- AD3552R_MASK_CH(0),
+- AD3552R_MASK_CH(1)
+- }
+-};
+-
+ static u8 _ad3552r_reg_len(u8 addr)
+ {
+ switch (addr) {
+@@ -399,11 +321,6 @@ static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val)
+ return 0;
+ }
+
+-static u16 ad3552r_field_prep(u16 val, u16 mask)
+-{
+- return (val << __ffs(mask)) & mask;
+-}
+-
+ /* Update field of a register, shift val if needed */
+ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
+ u16 val)
+@@ -416,21 +333,11 @@ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask,
+ return ret;
+
+ reg &= ~mask;
+- reg |= ad3552r_field_prep(val, mask);
++ reg |= val;
+
+ return ad3552r_write_reg(dac, addr, reg);
+ }
+
+-static int ad3552r_set_ch_value(struct ad3552r_desc *dac,
+- enum ad3552r_ch_attributes attr,
+- u8 ch,
+- u16 val)
+-{
+- /* Update register related to attributes in chip */
+- return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0],
+- addr_mask_map_ch[attr][ch + 1], val);
+-}
+-
+ #define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \
+ .type = IIO_VOLTAGE, \
+ .output = true, \
+@@ -510,8 +417,14 @@ static int ad3552r_write_raw(struct iio_dev *indio_dev,
+ val);
+ break;
+ case IIO_CHAN_INFO_ENABLE:
+- err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN,
+- chan->channel, !val);
++ if (chan->channel == 0)
++ val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(0), !val);
++ else
++ val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(1), !val);
++
++ err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG,
++ AD3552R_MASK_CH_DAC_POWERDOWN(chan->channel),
++ val);
+ break;
+ default:
+ err = -EINVAL;
+@@ -721,9 +634,9 @@ static int ad3552r_reset(struct ad3552r_desc *dac)
+ return ret;
+
+ return ad3552r_update_reg_field(dac,
+- addr_mask_map[AD3552R_ADDR_ASCENSION][0],
+- addr_mask_map[AD3552R_ADDR_ASCENSION][1],
+- val);
++ AD3552R_REG_ADDR_INTERFACE_CONFIG_A,
++ AD3552R_MASK_ADDR_ASCENSION,
++ FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val));
+ }
+
+ static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min,
+@@ -818,20 +731,20 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
+ "mandatory custom-output-range-config property missing\n");
+
+ dac->ch_data[ch].range_override = 1;
+- reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE);
++ reg |= FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1);
+
+ err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
+ if (err)
+ return dev_err_probe(dev, err,
+ "mandatory adi,gain-scaling-p property missing\n");
+- reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P);
++ reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, val);
+ dac->ch_data[ch].p = val;
+
+ err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
+ if (err)
+ return dev_err_probe(dev, err,
+ "mandatory adi,gain-scaling-n property missing\n");
+- reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N);
++ reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, val);
+ dac->ch_data[ch].n = val;
+
+ err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
+@@ -847,9 +760,9 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
+ dac->ch_data[ch].gain_offset = val;
+
+ offset = abs((s32)val);
+- reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8);
++ reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, (offset >> 8));
+
+- reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY);
++ reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)val < 0);
+ addr = AD3552R_REG_ADDR_CH_GAIN(ch);
+ err = ad3552r_write_reg(dac, addr,
+ offset & AD3552R_MASK_CH_OFFSET_BITS_0_7);
+@@ -892,9 +805,9 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ }
+
+ err = ad3552r_update_reg_field(dac,
+- addr_mask_map[AD3552R_VREF_SELECT][0],
+- addr_mask_map[AD3552R_VREF_SELECT][1],
+- val);
++ AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
++ AD3552R_MASK_REFERENCE_VOLTAGE_SEL,
++ FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val));
+ if (err)
+ return err;
+
+@@ -906,9 +819,9 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ }
+
+ err = ad3552r_update_reg_field(dac,
+- addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0],
+- addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1],
+- val);
++ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
++ AD3552R_MASK_SDO_DRIVE_STRENGTH,
++ FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val));
+ if (err)
+ return err;
+ }
+@@ -944,9 +857,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ "Invalid adi,output-range-microvolt value\n");
+
+ val = err;
+- err = ad3552r_set_ch_value(dac,
+- AD3552R_CH_OUTPUT_RANGE_SEL,
+- ch, val);
++ if (ch == 0)
++ val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val);
++ else
++ val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), val);
++
++ err = ad3552r_update_reg_field(dac,
++ AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE,
++ AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch),
++ val);
+ if (err)
+ return err;
+
+@@ -964,7 +883,14 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ ad3552r_calc_gain_and_offset(dac, ch);
+ dac->enabled_ch |= BIT(ch);
+
+- err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1);
++ if (ch == 0)
++ val = FIELD_PREP(AD3552R_MASK_CH(0), 1);
++ else
++ val = FIELD_PREP(AD3552R_MASK_CH(1), 1);
++
++ err = ad3552r_update_reg_field(dac,
++ AD3552R_REG_ADDR_CH_SELECT_16B,
++ AD3552R_MASK_CH(ch), val);
+ if (err < 0)
+ return err;
+
+@@ -976,8 +902,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ /* Disable unused channels */
+ for_each_clear_bit(ch, &dac->enabled_ch,
+ dac->model_data->num_hw_channels) {
+- err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN,
+- ch, 1);
++ if (ch == 0)
++ val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), 1);
++ else
++ val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1), 1);
++
++ err = ad3552r_update_reg_field(dac,
++ AD3552R_REG_ADDR_POWERDOWN_CONFIG,
++ AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch),
++ val);
+ if (err)
+ return err;
+ }
+--
+2.39.5
+
diff --git a/queue-6.12/iio-dac-ad3552r-common-fix-ad3541-2r-ranges.patch b/queue-6.12/iio-dac-ad3552r-common-fix-ad3541-2r-ranges.patch
new file mode 100644
index 0000000000..16b62681be
--- /dev/null
+++ b/queue-6.12/iio-dac-ad3552r-common-fix-ad3541-2r-ranges.patch
@@ -0,0 +1,95 @@
+From 4523a5cc80cc03d3ab8c0621c385dacf8aa02de8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Jan 2025 18:29:15 +0100
+Subject: iio: dac: ad3552r-common: fix ad3541/2r ranges
+
+From: Angelo Dureghello <adureghello@baylibre.com>
+
+[ Upstream commit 1e758b613212b6964518a67939535910b5aee831 ]
+
+Fix ad3541/2r voltage ranges to be as per ad3542r datasheet,
+rev. C, table 38 (page 57).
+
+The wrong ad354xr ranges was generating erroneous Vpp output.
+
+In more details:
+- fix wrong number of ranges, they are 5 ranges, not 6,
+- remove non-existent 0-3V range,
+- adjust order, since ad3552r_find_range() get a wrong index,
+ producing a wrong Vpp as output.
+
+Retested all the ranges on real hardware, EVALAD3542RFMCZ:
+
+adi,output-range-microvolt (fdt):
+<(000000) (2500000)>; ok (Rfbx1, switch 10)
+<(000000) (5000000)>; ok (Rfbx1, switch 10)
+<(000000) (10000000)>; ok (Rfbx1, switch 10)
+<(-5000000) (5000000)>; ok (Rfbx2, switch +/- 5)
+<(-2500000) (7500000)>; ok (Rfbx2, switch -2.5/7.5)
+
+Fixes: 8f2b54824b28 ("drivers:iio:dac: Add AD3552R driver support")
+Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
+Reviewed-by: David Lechner <dlechner@baylibre.com>
+Link: https://patch.msgid.link/20250108-wip-bl-ad3552r-axi-v0-iio-testing-carlos-v2-1-2dac02f04638@baylibre.com
+Cc: <Stable@vger.kernel.org>
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/dac/ad3552r-common.c | 5 ++---
+ drivers/iio/dac/ad3552r.h | 9 ++++-----
+ 2 files changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c
+index 2dfeca3656d21..94869ad15c27e 100644
+--- a/drivers/iio/dac/ad3552r-common.c
++++ b/drivers/iio/dac/ad3552r-common.c
+@@ -22,11 +22,10 @@ EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, IIO_AD3552R);
+
+ const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = {
+ [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 },
+- [AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 },
+ [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 },
+ [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 },
+- [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 },
+- [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }
++ [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 },
++ [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 }
+ };
+ EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, IIO_AD3552R);
+
+diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h
+index 7511e3f1882cb..c20f64f80d5db 100644
+--- a/drivers/iio/dac/ad3552r.h
++++ b/drivers/iio/dac/ad3552r.h
+@@ -128,7 +128,8 @@
+ #define AD3552R_LDAC_PULSE_US 100
+
+ #define AD3552R_MAX_RANGES 5
+-#define AD3542R_MAX_RANGES 6
++#define AD3542R_MAX_RANGES 5
++#define AD3552R_QUAD_SPI 2
+
+ extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2];
+ extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2];
+@@ -185,16 +186,14 @@ enum ad3552r_ch_vref_select {
+ enum ad3542r_ch_output_range {
+ /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
+ AD3542R_CH_OUTPUT_RANGE_0__2P5V,
+- /* Range from 0 V to 3 V. Requires Rfb1x connection */
+- AD3542R_CH_OUTPUT_RANGE_0__3V,
+ /* Range from 0 V to 5 V. Requires Rfb1x connection */
+ AD3542R_CH_OUTPUT_RANGE_0__5V,
+ /* Range from 0 V to 10 V. Requires Rfb2x connection */
+ AD3542R_CH_OUTPUT_RANGE_0__10V,
+- /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
+- AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
+ /* Range from -5 V to 5 V. Requires Rfb2x connection */
+ AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
++ /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
++ AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
+ };
+
+ enum ad3552r_ch_output_range {
+--
+2.39.5
+
diff --git a/queue-6.12/iio-dac-ad3552r-extract-common-code-no-changes-in-be.patch b/queue-6.12/iio-dac-ad3552r-extract-common-code-no-changes-in-be.patch
new file mode 100644
index 0000000000..4c83641978
--- /dev/null
+++ b/queue-6.12/iio-dac-ad3552r-extract-common-code-no-changes-in-be.patch
@@ -0,0 +1,1002 @@
+From 96255fea746ff28e655fa04a9003bba5f29a9dbc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Oct 2024 22:45:33 +0100
+Subject: iio: dac: ad3552r: extract common code (no changes in behavior
+ intended)
+
+From: Angelo Dureghello <adureghello@baylibre.com>
+
+[ Upstream commit f665d7d33d7909cf51e2db0f0767ecab0295c0bd ]
+
+Extracting common code, to share common code to be used later
+by the AXI driver version (ad3552r-axi.c).
+
+Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
+Reviewed-by: David Lechner <dlechner@baylibre.com>
+Link: https://patch.msgid.link/20241028-wip-bl-ad3552r-axi-v0-iio-testing-v9-6-f6960b4f9719@kernel-space.org
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/dac/Makefile | 2 +-
+ drivers/iio/dac/ad3552r-common.c | 249 +++++++++++++++++++
+ drivers/iio/dac/ad3552r.c | 398 +++----------------------------
+ drivers/iio/dac/ad3552r.h | 224 +++++++++++++++++
+ 4 files changed, 501 insertions(+), 372 deletions(-)
+ create mode 100644 drivers/iio/dac/ad3552r-common.c
+ create mode 100644 drivers/iio/dac/ad3552r.h
+
+diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
+index 2cf148f16306d..56a125f56284f 100644
+--- a/drivers/iio/dac/Makefile
++++ b/drivers/iio/dac/Makefile
+@@ -4,7 +4,7 @@
+ #
+
+ # When adding new entries keep the list in alphabetical order
+-obj-$(CONFIG_AD3552R) += ad3552r.o
++obj-$(CONFIG_AD3552R) += ad3552r.o ad3552r-common.o
+ obj-$(CONFIG_AD5360) += ad5360.o
+ obj-$(CONFIG_AD5380) += ad5380.o
+ obj-$(CONFIG_AD5421) += ad5421.o
+diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c
+new file mode 100644
+index 0000000000000..2dfeca3656d21
+--- /dev/null
++++ b/drivers/iio/dac/ad3552r-common.c
+@@ -0,0 +1,249 @@
++// SPDX-License-Identifier: GPL-2.0+
++//
++// Copyright (c) 2010-2024 Analog Devices Inc.
++// Copyright (c) 2024 Baylibre, SAS
++
++#include <linux/bitfield.h>
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/property.h>
++#include <linux/regulator/consumer.h>
++
++#include "ad3552r.h"
++
++const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = {
++ [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 },
++ [AD3552R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 },
++ [AD3552R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 },
++ [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 },
++ [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = { -10000, 10000 }
++};
++EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, IIO_AD3552R);
++
++const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = {
++ [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 },
++ [AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 },
++ [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 },
++ [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 },
++ [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 },
++ [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }
++};
++EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, IIO_AD3552R);
++
++/* Gain * AD3552R_GAIN_SCALE */
++static const s32 gains_scaling_table[] = {
++ [AD3552R_CH_GAIN_SCALING_1] = 1000,
++ [AD3552R_CH_GAIN_SCALING_0_5] = 500,
++ [AD3552R_CH_GAIN_SCALING_0_25] = 250,
++ [AD3552R_CH_GAIN_SCALING_0_125] = 125
++};
++
++u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs)
++{
++ return FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1) |
++ FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p) |
++ FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n) |
++ FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs(goffs)) |
++ FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, goffs < 0);
++}
++EXPORT_SYMBOL_NS_GPL(ad3552r_calc_custom_gain, IIO_AD3552R);
++
++static void ad3552r_get_custom_range(struct ad3552r_ch_data *ch_data,
++ s32 *v_min, s32 *v_max)
++{
++ s64 vref, tmp, common, offset, gn, gp;
++ /*
++ * From datasheet formula (In Volts):
++ * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03]
++ * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03]
++ * Calculus are converted to milivolts
++ */
++ vref = 2500;
++ /* 2.5 * 1.03 * 1000 (To mV) */
++ common = 2575 * ch_data->rfb;
++ offset = ch_data->gain_offset;
++
++ gn = gains_scaling_table[ch_data->n];
++ tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common;
++ tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
++ *v_max = vref + tmp;
++
++ gp = gains_scaling_table[ch_data->p];
++ tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common;
++ tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
++ *v_min = vref - tmp;
++}
++
++void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data,
++ const struct ad3552r_model_data *model_data)
++{
++ s32 idx, v_max, v_min, span, rem;
++ s64 tmp;
++
++ if (ch_data->range_override) {
++ ad3552r_get_custom_range(ch_data, &v_min, &v_max);
++ } else {
++ /* Normal range */
++ idx = ch_data->range;
++ v_min = model_data->ranges_table[idx][0];
++ v_max = model_data->ranges_table[idx][1];
++ }
++
++ /*
++ * From datasheet formula:
++ * Vout = Span * (D / 65536) + Vmin
++ * Converted to scale and offset:
++ * Scale = Span / 65536
++ * Offset = 65536 * Vmin / Span
++ *
++ * Reminders are in micros in order to be printed as
++ * IIO_VAL_INT_PLUS_MICRO
++ */
++ span = v_max - v_min;
++ ch_data->scale_int = div_s64_rem(span, 65536, &rem);
++ /* Do operations in microvolts */
++ ch_data->scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, 65536);
++
++ ch_data->offset_int = div_s64_rem(v_min * 65536, span, &rem);
++ tmp = (s64)rem * 1000000;
++ ch_data->offset_dec = div_s64(tmp, span);
++}
++EXPORT_SYMBOL_NS_GPL(ad3552r_calc_gain_and_offset, IIO_AD3552R);
++
++int ad3552r_get_ref_voltage(struct device *dev, u32 *val)
++{
++ int voltage;
++ int delta = 100000;
++
++ voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
++ if (voltage < 0 && voltage != -ENODEV)
++ return dev_err_probe(dev, voltage,
++ "Error getting vref voltage\n");
++
++ if (voltage == -ENODEV) {
++ if (device_property_read_bool(dev, "adi,vref-out-en"))
++ *val = AD3552R_INTERNAL_VREF_PIN_2P5V;
++ else
++ *val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
++
++ return 0;
++ }
++
++ if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
++ dev_warn(dev, "vref-supply must be 2.5V");
++ return -EINVAL;
++ }
++
++ *val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
++
++ return 0;
++}
++EXPORT_SYMBOL_NS_GPL(ad3552r_get_ref_voltage, IIO_AD3552R);
++
++int ad3552r_get_drive_strength(struct device *dev, u32 *val)
++{
++ int err;
++ u32 drive_strength;
++
++ err = device_property_read_u32(dev, "adi,sdo-drive-strength",
++ &drive_strength);
++ if (err)
++ return err;
++
++ if (drive_strength > 3) {
++ dev_err_probe(dev, -EINVAL,
++ "adi,sdo-drive-strength must be less than 4\n");
++ return -EINVAL;
++ }
++
++ *val = drive_strength;
++
++ return 0;
++}
++EXPORT_SYMBOL_NS_GPL(ad3552r_get_drive_strength, IIO_AD3552R);
++
++int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
++ u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs)
++{
++ int err;
++ u32 val;
++ struct fwnode_handle *gain_child __free(fwnode_handle) =
++ fwnode_get_named_child_node(child,
++ "custom-output-range-config");
++
++ if (!gain_child)
++ return dev_err_probe(dev, -EINVAL,
++ "custom-output-range-config mandatory\n");
++
++ err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
++ if (err)
++ return dev_err_probe(dev, err,
++ "adi,gain-scaling-p mandatory\n");
++ *gs_p = val;
++
++ err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
++ if (err)
++ return dev_err_probe(dev, err,
++ "adi,gain-scaling-n property mandatory\n");
++ *gs_n = val;
++
++ err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
++ if (err)
++ return dev_err_probe(dev, err,
++ "adi,rfb-ohms mandatory\n");
++ *rfb = val;
++
++ err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
++ if (err)
++ return dev_err_probe(dev, err,
++ "adi,gain-offset mandatory\n");
++ *goffs = val;
++
++ return 0;
++}
++EXPORT_SYMBOL_NS_GPL(ad3552r_get_custom_gain, IIO_AD3552R);
++
++static int ad3552r_find_range(const struct ad3552r_model_data *model_info,
++ s32 *vals)
++{
++ int i;
++
++ for (i = 0; i < model_info->num_ranges; i++)
++ if (vals[0] == model_info->ranges_table[i][0] * 1000 &&
++ vals[1] == model_info->ranges_table[i][1] * 1000)
++ return i;
++
++ return -EINVAL;
++}
++
++int ad3552r_get_output_range(struct device *dev,
++ const struct ad3552r_model_data *model_info,
++ struct fwnode_handle *child, u32 *val)
++{
++ int ret;
++ s32 vals[2];
++
++ /* This property is optional, so returning -ENOENT if missing */
++ if (!fwnode_property_present(child, "adi,output-range-microvolt"))
++ return -ENOENT;
++
++ ret = fwnode_property_read_u32_array(child,
++ "adi,output-range-microvolt",
++ vals, 2);
++ if (ret)
++ return dev_err_probe(dev, ret,
++ "invalid adi,output-range-microvolt\n");
++
++ ret = ad3552r_find_range(model_info, vals);
++ if (ret < 0)
++ return dev_err_probe(dev, ret,
++ "invalid adi,output-range-microvolt value\n");
++
++ *val = ret;
++
++ return 0;
++}
++EXPORT_SYMBOL_NS_GPL(ad3552r_get_output_range, IIO_AD3552R);
++
++MODULE_DESCRIPTION("ad3552r common functions");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c
+index aa453d3de5e1c..5b2ce2aa67a47 100644
+--- a/drivers/iio/dac/ad3552r.c
++++ b/drivers/iio/dac/ad3552r.c
+@@ -12,226 +12,9 @@
+ #include <linux/iio/trigger_consumer.h>
+ #include <linux/iopoll.h>
+ #include <linux/kernel.h>
+-#include <linux/regulator/consumer.h>
+ #include <linux/spi/spi.h>
+
+-/* Register addresses */
+-/* Primary address space */
+-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00
+-#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0))
+-#define AD3552R_MASK_ADDR_ASCENSION BIT(5)
+-#define AD3552R_MASK_SDO_ACTIVE BIT(4)
+-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01
+-#define AD3552R_MASK_SINGLE_INST BIT(7)
+-#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3)
+-#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02
+-#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n))
+-#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2)
+-#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0)
+-#define AD3552R_REG_ADDR_CHIP_TYPE 0x03
+-#define AD3552R_MASK_CLASS GENMASK(7, 0)
+-#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04
+-#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05
+-#define AD3552R_REG_ADDR_CHIP_GRADE 0x06
+-#define AD3552R_MASK_GRADE GENMASK(7, 4)
+-#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0)
+-#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A
+-#define AD3552R_REG_ADDR_SPI_REVISION 0x0B
+-#define AD3552R_REG_ADDR_VENDOR_L 0x0C
+-#define AD3552R_REG_ADDR_VENDOR_H 0x0D
+-#define AD3552R_REG_ADDR_STREAM_MODE 0x0E
+-#define AD3552R_MASK_LENGTH GENMASK(7, 0)
+-#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F
+-#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6)
+-#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2)
+-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10
+-#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\
+- GENMASK(1, 0))
+-#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5)
+-#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11
+-#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7)
+-#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5)
+-#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3)
+-#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2)
+-#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1)
+-#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0)
+-#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14
+-#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6)
+-#define AD3552R_MASK_MEM_CRC_EN BIT(4)
+-#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2)
+-#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1)
+-#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0)
+-#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15
+-#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6)
+-#define AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN BIT(5)
+-#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3)
+-#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2)
+-#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0)
+-#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16
+-#define AD3552R_MASK_REF_RANGE_ALARM BIT(6)
+-#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5)
+-#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4)
+-#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3)
+-#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2)
+-#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1)
+-#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0)
+-#define AD3552R_REG_ADDR_ERR_STATUS 0x17
+-#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6)
+-#define AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5)
+-#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4)
+-#define AD3552R_MASK_RESET_STATUS BIT(0)
+-#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18
+-#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch))
+-#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch)
+-#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19
+-#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? GENMASK(7, 4) :\
+- GENMASK(3, 0))
+-#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2)
+-#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0)
+-#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2)
+-#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7)
+-#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5)
+-#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3)
+-#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2)
+-#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(0)
+-/*
+- * Secondary region
+- * For multibyte registers specify the highest address because the access is
+- * done in descending order
+- */
+-#define AD3552R_SECONDARY_REGION_START 0x28
+-#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28
+-#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - ch) * 2)
+-#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E
+-#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F
+-#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31
+-#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32
+-#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - ch) * 2)
+-/* 3 bytes registers */
+-#define AD3552R_REG_START_24B 0x37
+-#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37
+-#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - ch) * 3)
+-#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40
+-#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41
+-#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44
+-#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45
+-#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3)
+-
+-/* Useful defines */
+-#define AD3552R_MAX_CH 2
+-#define AD3552R_MASK_CH(ch) BIT(ch)
+-#define AD3552R_MASK_ALL_CH GENMASK(1, 0)
+-#define AD3552R_MAX_REG_SIZE 3
+-#define AD3552R_READ_BIT BIT(7)
+-#define AD3552R_ADDR_MASK GENMASK(6, 0)
+-#define AD3552R_MASK_DAC_12B 0xFFF0
+-#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8
+-#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34
+-#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2
+-#define AD3552R_GAIN_SCALE 1000
+-#define AD3552R_LDAC_PULSE_US 100
+-
+-enum ad3552r_ch_vref_select {
+- /* Internal source with Vref I/O floating */
+- AD3552R_INTERNAL_VREF_PIN_FLOATING,
+- /* Internal source with Vref I/O at 2.5V */
+- AD3552R_INTERNAL_VREF_PIN_2P5V,
+- /* External source with Vref I/O as input */
+- AD3552R_EXTERNAL_VREF_PIN_INPUT
+-};
+-
+-enum ad3552r_id {
+- AD3541R_ID = 0x400b,
+- AD3542R_ID = 0x4009,
+- AD3551R_ID = 0x400a,
+- AD3552R_ID = 0x4008,
+-};
+-
+-enum ad3552r_ch_output_range {
+- /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
+- AD3552R_CH_OUTPUT_RANGE_0__2P5V,
+- /* Range from 0 V to 5 V. Requires Rfb1x connection */
+- AD3552R_CH_OUTPUT_RANGE_0__5V,
+- /* Range from 0 V to 10 V. Requires Rfb2x connection */
+- AD3552R_CH_OUTPUT_RANGE_0__10V,
+- /* Range from -5 V to 5 V. Requires Rfb2x connection */
+- AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
+- /* Range from -10 V to 10 V. Requires Rfb4x connection */
+- AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
+-};
+-
+-static const s32 ad3552r_ch_ranges[][2] = {
+- [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500},
+- [AD3552R_CH_OUTPUT_RANGE_0__5V] = {0, 5000},
+- [AD3552R_CH_OUTPUT_RANGE_0__10V] = {0, 10000},
+- [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000},
+- [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = {-10000, 10000}
+-};
+-
+-enum ad3542r_ch_output_range {
+- /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
+- AD3542R_CH_OUTPUT_RANGE_0__2P5V,
+- /* Range from 0 V to 3 V. Requires Rfb1x connection */
+- AD3542R_CH_OUTPUT_RANGE_0__3V,
+- /* Range from 0 V to 5 V. Requires Rfb1x connection */
+- AD3542R_CH_OUTPUT_RANGE_0__5V,
+- /* Range from 0 V to 10 V. Requires Rfb2x connection */
+- AD3542R_CH_OUTPUT_RANGE_0__10V,
+- /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
+- AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
+- /* Range from -5 V to 5 V. Requires Rfb2x connection */
+- AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
+-};
+-
+-static const s32 ad3542r_ch_ranges[][2] = {
+- [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500},
+- [AD3542R_CH_OUTPUT_RANGE_0__3V] = {0, 3000},
+- [AD3542R_CH_OUTPUT_RANGE_0__5V] = {0, 5000},
+- [AD3542R_CH_OUTPUT_RANGE_0__10V] = {0, 10000},
+- [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = {-2500, 7500},
+- [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000}
+-};
+-
+-enum ad3552r_ch_gain_scaling {
+- /* Gain scaling of 1 */
+- AD3552R_CH_GAIN_SCALING_1,
+- /* Gain scaling of 0.5 */
+- AD3552R_CH_GAIN_SCALING_0_5,
+- /* Gain scaling of 0.25 */
+- AD3552R_CH_GAIN_SCALING_0_25,
+- /* Gain scaling of 0.125 */
+- AD3552R_CH_GAIN_SCALING_0_125,
+-};
+-
+-/* Gain * AD3552R_GAIN_SCALE */
+-static const s32 gains_scaling_table[] = {
+- [AD3552R_CH_GAIN_SCALING_1] = 1000,
+- [AD3552R_CH_GAIN_SCALING_0_5] = 500,
+- [AD3552R_CH_GAIN_SCALING_0_25] = 250,
+- [AD3552R_CH_GAIN_SCALING_0_125] = 125
+-};
+-
+-struct ad3552r_ch_data {
+- s32 scale_int;
+- s32 scale_dec;
+- s32 offset_int;
+- s32 offset_dec;
+- s16 gain_offset;
+- u16 rfb;
+- u8 n;
+- u8 p;
+- u8 range;
+- bool range_override;
+-};
+-
+-struct ad3552r_model_data {
+- const char *model_name;
+- enum ad3552r_id chip_id;
+- unsigned int num_hw_channels;
+- const s32 (*ranges_table)[2];
+- int num_ranges;
+- bool requires_output_range;
+-};
++#include "ad3552r.h"
+
+ struct ad3552r_desc {
+ const struct ad3552r_model_data *model_data;
+@@ -639,136 +422,35 @@ static int ad3552r_reset(struct ad3552r_desc *dac)
+ FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val));
+ }
+
+-static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min,
+- s32 *v_max)
+-{
+- s64 vref, tmp, common, offset, gn, gp;
+- /*
+- * From datasheet formula (In Volts):
+- * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03]
+- * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03]
+- * Calculus are converted to milivolts
+- */
+- vref = 2500;
+- /* 2.5 * 1.03 * 1000 (To mV) */
+- common = 2575 * dac->ch_data[i].rfb;
+- offset = dac->ch_data[i].gain_offset;
+-
+- gn = gains_scaling_table[dac->ch_data[i].n];
+- tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common;
+- tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
+- *v_max = vref + tmp;
+-
+- gp = gains_scaling_table[dac->ch_data[i].p];
+- tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common;
+- tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE);
+- *v_min = vref - tmp;
+-}
+-
+-static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch)
+-{
+- s32 idx, v_max, v_min, span, rem;
+- s64 tmp;
+-
+- if (dac->ch_data[ch].range_override) {
+- ad3552r_get_custom_range(dac, ch, &v_min, &v_max);
+- } else {
+- /* Normal range */
+- idx = dac->ch_data[ch].range;
+- v_min = dac->model_data->ranges_table[idx][0];
+- v_max = dac->model_data->ranges_table[idx][1];
+- }
+-
+- /*
+- * From datasheet formula:
+- * Vout = Span * (D / 65536) + Vmin
+- * Converted to scale and offset:
+- * Scale = Span / 65536
+- * Offset = 65536 * Vmin / Span
+- *
+- * Reminders are in micros in order to be printed as
+- * IIO_VAL_INT_PLUS_MICRO
+- */
+- span = v_max - v_min;
+- dac->ch_data[ch].scale_int = div_s64_rem(span, 65536, &rem);
+- /* Do operations in microvolts */
+- dac->ch_data[ch].scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000,
+- 65536);
+-
+- dac->ch_data[ch].offset_int = div_s64_rem(v_min * 65536, span, &rem);
+- tmp = (s64)rem * 1000000;
+- dac->ch_data[ch].offset_dec = div_s64(tmp, span);
+-}
+-
+-static int ad3552r_find_range(const struct ad3552r_model_data *model_data,
+- s32 *vals)
+-{
+- int i;
+-
+- for (i = 0; i < model_data->num_ranges; i++)
+- if (vals[0] == model_data->ranges_table[i][0] * 1000 &&
+- vals[1] == model_data->ranges_table[i][1] * 1000)
+- return i;
+-
+- return -EINVAL;
+-}
+-
+ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
+ struct fwnode_handle *child,
+ u32 ch)
+ {
+ struct device *dev = &dac->spi->dev;
+- u32 val;
+ int err;
+ u8 addr;
+- u16 reg = 0, offset;
+-
+- struct fwnode_handle *gain_child __free(fwnode_handle)
+- = fwnode_get_named_child_node(child,
+- "custom-output-range-config");
+- if (!gain_child)
+- return dev_err_probe(dev, -EINVAL,
+- "mandatory custom-output-range-config property missing\n");
+-
+- dac->ch_data[ch].range_override = 1;
+- reg |= FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1);
+-
+- err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val);
+- if (err)
+- return dev_err_probe(dev, err,
+- "mandatory adi,gain-scaling-p property missing\n");
+- reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, val);
+- dac->ch_data[ch].p = val;
+-
+- err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val);
+- if (err)
+- return dev_err_probe(dev, err,
+- "mandatory adi,gain-scaling-n property missing\n");
+- reg |= FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, val);
+- dac->ch_data[ch].n = val;
+-
+- err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val);
+- if (err)
+- return dev_err_probe(dev, err,
+- "mandatory adi,rfb-ohms property missing\n");
+- dac->ch_data[ch].rfb = val;
++ u16 reg;
+
+- err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val);
++ err = ad3552r_get_custom_gain(dev, child,
++ &dac->ch_data[ch].p,
++ &dac->ch_data[ch].n,
++ &dac->ch_data[ch].rfb,
++ &dac->ch_data[ch].gain_offset);
+ if (err)
+- return dev_err_probe(dev, err,
+- "mandatory adi,gain-offset property missing\n");
+- dac->ch_data[ch].gain_offset = val;
++ return err;
+
+- offset = abs((s32)val);
+- reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, (offset >> 8));
++ dac->ch_data[ch].range_override = 1;
+
+- reg |= FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, (s32)val < 0);
+ addr = AD3552R_REG_ADDR_CH_GAIN(ch);
+ err = ad3552r_write_reg(dac, addr,
+- offset & AD3552R_MASK_CH_OFFSET_BITS_0_7);
++ abs((s32)dac->ch_data[ch].gain_offset) &
++ AD3552R_MASK_CH_OFFSET_BITS_0_7);
+ if (err)
+ return dev_err_probe(dev, err, "Error writing register\n");
+
++ reg = ad3552r_calc_custom_gain(dac->ch_data[ch].p, dac->ch_data[ch].n,
++ dac->ch_data[ch].gain_offset);
++
+ err = ad3552r_write_reg(dac, addr, reg);
+ if (err)
+ return dev_err_probe(dev, err, "Error writing register\n");
+@@ -779,30 +461,17 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac,
+ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ {
+ struct device *dev = &dac->spi->dev;
+- int err, cnt = 0, voltage, delta = 100000;
+- u32 vals[2], val, ch;
++ int err, cnt = 0;
++ u32 val, ch;
+
+ dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH);
+ if (IS_ERR(dac->gpio_ldac))
+ return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac),
+ "Error getting gpio ldac");
+
+- voltage = devm_regulator_get_enable_read_voltage(dev, "vref");
+- if (voltage < 0 && voltage != -ENODEV)
+- return dev_err_probe(dev, voltage, "Error getting vref voltage\n");
+-
+- if (voltage == -ENODEV) {
+- if (device_property_read_bool(dev, "adi,vref-out-en"))
+- val = AD3552R_INTERNAL_VREF_PIN_2P5V;
+- else
+- val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
+- } else {
+- if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
+- dev_warn(dev, "vref-supply must be 2.5V");
+- return -EINVAL;
+- }
+- val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
+- }
++ err = ad3552r_get_ref_voltage(dev, &val);
++ if (err < 0)
++ return err;
+
+ err = ad3552r_update_reg_field(dac,
+ AD3552R_REG_ADDR_SH_REFERENCE_CONFIG,
+@@ -811,13 +480,8 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ if (err)
+ return err;
+
+- err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val);
++ err = ad3552r_get_drive_strength(dev, &val);
+ if (!err) {
+- if (val > 3) {
+- dev_err(dev, "adi,sdo-drive-strength must be less than 4\n");
+- return -EINVAL;
+- }
+-
+ err = ad3552r_update_reg_field(dac,
+ AD3552R_REG_ADDR_INTERFACE_CONFIG_D,
+ AD3552R_MASK_SDO_DRIVE_STRENGTH,
+@@ -842,21 +506,12 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ "reg must be less than %d\n",
+ dac->model_data->num_hw_channels);
+
+- if (fwnode_property_present(child, "adi,output-range-microvolt")) {
+- err = fwnode_property_read_u32_array(child,
+- "adi,output-range-microvolt",
+- vals,
+- 2);
+- if (err)
+- return dev_err_probe(dev, err,
+- "adi,output-range-microvolt property could not be parsed\n");
+-
+- err = ad3552r_find_range(dac->model_data, vals);
+- if (err < 0)
+- return dev_err_probe(dev, err,
+- "Invalid adi,output-range-microvolt value\n");
++ err = ad3552r_get_output_range(dev, dac->model_data,
++ child, &val);
++ if (err && err != -ENOENT)
++ return err;
+
+- val = err;
++ if (!err) {
+ if (ch == 0)
+ val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val);
+ else
+@@ -880,7 +535,7 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac)
+ return err;
+ }
+
+- ad3552r_calc_gain_and_offset(dac, ch);
++ ad3552r_calc_gain_and_offset(&dac->ch_data[ch], dac->model_data);
+ dac->enabled_ch |= BIT(ch);
+
+ if (ch == 0)
+@@ -1079,3 +734,4 @@ module_spi_driver(ad3552r_driver);
+ MODULE_AUTHOR("Mihail Chindris <mihail.chindris@analog.com>");
+ MODULE_DESCRIPTION("Analog Device AD3552R DAC");
+ MODULE_LICENSE("GPL v2");
++MODULE_IMPORT_NS(IIO_AD3552R);
+diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h
+new file mode 100644
+index 0000000000000..7511e3f1882cb
+--- /dev/null
++++ b/drivers/iio/dac/ad3552r.h
+@@ -0,0 +1,224 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * AD3552R Digital <-> Analog converters common header
++ *
++ * Copyright 2021-2024 Analog Devices Inc.
++ * Author: Angelo Dureghello <adureghello@baylibre.com>
++ */
++
++#ifndef __DRIVERS_IIO_DAC_AD3552R_H__
++#define __DRIVERS_IIO_DAC_AD3552R_H__
++
++/* Register addresses */
++/* Primary address space */
++#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00
++#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0))
++#define AD3552R_MASK_ADDR_ASCENSION BIT(5)
++#define AD3552R_MASK_SDO_ACTIVE BIT(4)
++#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01
++#define AD3552R_MASK_SINGLE_INST BIT(7)
++#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3)
++#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02
++#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n))
++#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2)
++#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0)
++#define AD3552R_REG_ADDR_CHIP_TYPE 0x03
++#define AD3552R_MASK_CLASS GENMASK(7, 0)
++#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04
++#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05
++#define AD3552R_REG_ADDR_CHIP_GRADE 0x06
++#define AD3552R_MASK_GRADE GENMASK(7, 4)
++#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0)
++#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A
++#define AD3552R_REG_ADDR_SPI_REVISION 0x0B
++#define AD3552R_REG_ADDR_VENDOR_L 0x0C
++#define AD3552R_REG_ADDR_VENDOR_H 0x0D
++#define AD3552R_REG_ADDR_STREAM_MODE 0x0E
++#define AD3552R_MASK_LENGTH GENMASK(7, 0)
++#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F
++#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6)
++#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2)
++#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10
++#define AD3552R_MASK_CRC_ENABLE \
++ (GENMASK(7, 6) | GENMASK(1, 0))
++#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5)
++#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11
++#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7)
++#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5)
++#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3)
++#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2)
++#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1)
++#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0)
++#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14
++#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6)
++#define AD3552R_MASK_MEM_CRC_EN BIT(4)
++#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2)
++#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1)
++#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0)
++#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15
++#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6)
++#define AD3552R_MASK_SAMPLE_HOLD_DIFF_USER_EN BIT(5)
++#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3)
++#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2)
++#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0)
++#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16
++#define AD3552R_MASK_REF_RANGE_ALARM BIT(6)
++#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5)
++#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4)
++#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3)
++#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2)
++#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1)
++#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0)
++#define AD3552R_REG_ADDR_ERR_STATUS 0x17
++#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6)
++#define AD3552R_MASK_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5)
++#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4)
++#define AD3552R_MASK_RESET_STATUS BIT(0)
++#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18
++#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch))
++#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch)
++#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19
++#define AD3552R_MASK_CH0_RANGE GENMASK(2, 0)
++#define AD3552R_MASK_CH1_RANGE GENMASK(6, 4)
++#define AD3552R_MASK_CH_OUTPUT_RANGE GENMASK(7, 0)
++#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) \
++ ((ch) ? GENMASK(7, 4) : GENMASK(3, 0))
++#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2)
++#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0)
++#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2)
++#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7)
++#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5)
++#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3)
++#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2)
++#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(8)
++/*
++ * Secondary region
++ * For multibyte registers specify the highest address because the access is
++ * done in descending order
++ */
++#define AD3552R_SECONDARY_REGION_START 0x28
++#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28
++#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - (ch)) * 2)
++#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E
++#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F
++#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31
++#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32
++#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - (ch)) * 2)
++/* 3 bytes registers */
++#define AD3552R_REG_START_24B 0x37
++#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37
++#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - (ch)) * 3)
++#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40
++#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41
++#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44
++#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45
++#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - (ch)) * 3)
++
++#define AD3552R_MAX_CH 2
++#define AD3552R_MASK_CH(ch) BIT(ch)
++#define AD3552R_MASK_ALL_CH GENMASK(1, 0)
++#define AD3552R_MAX_REG_SIZE 3
++#define AD3552R_READ_BIT BIT(7)
++#define AD3552R_ADDR_MASK GENMASK(6, 0)
++#define AD3552R_MASK_DAC_12B GENMASK(15, 4)
++#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8
++#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34
++#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2
++#define AD3552R_GAIN_SCALE 1000
++#define AD3552R_LDAC_PULSE_US 100
++
++#define AD3552R_MAX_RANGES 5
++#define AD3542R_MAX_RANGES 6
++
++extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2];
++extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2];
++
++enum ad3552r_id {
++ AD3541R_ID = 0x400b,
++ AD3542R_ID = 0x4009,
++ AD3551R_ID = 0x400a,
++ AD3552R_ID = 0x4008,
++};
++
++struct ad3552r_model_data {
++ const char *model_name;
++ enum ad3552r_id chip_id;
++ unsigned int num_hw_channels;
++ const s32 (*ranges_table)[2];
++ int num_ranges;
++ bool requires_output_range;
++};
++
++struct ad3552r_ch_data {
++ s32 scale_int;
++ s32 scale_dec;
++ s32 offset_int;
++ s32 offset_dec;
++ s16 gain_offset;
++ u16 rfb;
++ u8 n;
++ u8 p;
++ u8 range;
++ bool range_override;
++};
++
++enum ad3552r_ch_gain_scaling {
++ /* Gain scaling of 1 */
++ AD3552R_CH_GAIN_SCALING_1,
++ /* Gain scaling of 0.5 */
++ AD3552R_CH_GAIN_SCALING_0_5,
++ /* Gain scaling of 0.25 */
++ AD3552R_CH_GAIN_SCALING_0_25,
++ /* Gain scaling of 0.125 */
++ AD3552R_CH_GAIN_SCALING_0_125,
++};
++
++enum ad3552r_ch_vref_select {
++ /* Internal source with Vref I/O floating */
++ AD3552R_INTERNAL_VREF_PIN_FLOATING,
++ /* Internal source with Vref I/O at 2.5V */
++ AD3552R_INTERNAL_VREF_PIN_2P5V,
++ /* External source with Vref I/O as input */
++ AD3552R_EXTERNAL_VREF_PIN_INPUT
++};
++
++enum ad3542r_ch_output_range {
++ /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
++ AD3542R_CH_OUTPUT_RANGE_0__2P5V,
++ /* Range from 0 V to 3 V. Requires Rfb1x connection */
++ AD3542R_CH_OUTPUT_RANGE_0__3V,
++ /* Range from 0 V to 5 V. Requires Rfb1x connection */
++ AD3542R_CH_OUTPUT_RANGE_0__5V,
++ /* Range from 0 V to 10 V. Requires Rfb2x connection */
++ AD3542R_CH_OUTPUT_RANGE_0__10V,
++ /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */
++ AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V,
++ /* Range from -5 V to 5 V. Requires Rfb2x connection */
++ AD3542R_CH_OUTPUT_RANGE_NEG_5__5V,
++};
++
++enum ad3552r_ch_output_range {
++ /* Range from 0 V to 2.5 V. Requires Rfb1x connection */
++ AD3552R_CH_OUTPUT_RANGE_0__2P5V,
++ /* Range from 0 V to 5 V. Requires Rfb1x connection */
++ AD3552R_CH_OUTPUT_RANGE_0__5V,
++ /* Range from 0 V to 10 V. Requires Rfb2x connection */
++ AD3552R_CH_OUTPUT_RANGE_0__10V,
++ /* Range from -5 V to 5 V. Requires Rfb2x connection */
++ AD3552R_CH_OUTPUT_RANGE_NEG_5__5V,
++ /* Range from -10 V to 10 V. Requires Rfb4x connection */
++ AD3552R_CH_OUTPUT_RANGE_NEG_10__10V,
++};
++
++int ad3552r_get_output_range(struct device *dev,
++ const struct ad3552r_model_data *model_info,
++ struct fwnode_handle *child, u32 *val);
++int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child,
++ u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs);
++u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs);
++int ad3552r_get_ref_voltage(struct device *dev, u32 *val);
++int ad3552r_get_drive_strength(struct device *dev, u32 *val);
++void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data,
++ const struct ad3552r_model_data *model_data);
++
++#endif /* __DRIVERS_IIO_DAC_AD3552R_H__ */
+--
+2.39.5
+
diff --git a/queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch b/queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch
new file mode 100644
index 0000000000..0a730fe17f
--- /dev/null
+++ b/queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch
@@ -0,0 +1,336 @@
+From 0510d3297a23920caf74a63e3f38c0ede70d6555 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Jul 2025 18:37:48 -0400
+Subject: KVM: arm64: Set HCR_EL2.TID1 unconditionally
+
+[ Upstream commit 4cd48565b0e5df398e7253c0d2d8c0403d69e7bf ]
+
+commit 90807748ca3a ("KVM: arm64: Hide SME system registers from
+guests") added trap handling for SMIDR_EL1, treating it as UNDEFINED as
+KVM does not support SME. This is right for the most part, however KVM
+needs to set HCR_EL2.TID1 to _actually_ trap the register.
+
+Unfortunately, this comes with some collateral damage as TID1 forces
+REVIDR_EL1 and AIDR_EL1 to trap as well. KVM has long treated these
+registers as "invariant" which is an awful term for the following:
+
+ - Userspace sees the boot CPU values on all vCPUs
+
+ - The guest sees the hardware values of the CPU on which a vCPU is
+ scheduled
+
+Keep the plates spinning by adding trap handling for the affected
+registers and repaint all of the "invariant" crud into terms of
+identifying an implementation. Yes, at this point we only need to
+set TID1 on SME hardware, but REVIDR_EL1 and AIDR_EL1 are about to
+become mutable anyway.
+
+Cc: Mark Brown <broonie@kernel.org>
+Cc: stable@vger.kernel.org
+Fixes: 90807748ca3a ("KVM: arm64: Hide SME system registers from guests")
+[maz: handle traps from 32bit]
+Co-developed-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/20250225005401.679536-2-oliver.upton@linux.dev
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/kvm_arm.h | 4 +-
+ arch/arm64/kvm/sys_regs.c | 184 +++++++++++++++++--------------
+ 2 files changed, 101 insertions(+), 87 deletions(-)
+
+diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
+index 109a85ee69100..dd34794cec997 100644
+--- a/arch/arm64/include/asm/kvm_arm.h
++++ b/arch/arm64/include/asm/kvm_arm.h
+@@ -92,12 +92,12 @@
+ * SWIO: Turn set/way invalidates into set/way clean+invalidate
+ * PTW: Take a stage2 fault if a stage1 walk steps in device memory
+ * TID3: Trap EL1 reads of group 3 ID registers
+- * TID2: Trap CTR_EL0, CCSIDR2_EL1, CLIDR_EL1, and CSSELR_EL1
++ * TID1: Trap REVIDR_EL1, AIDR_EL1, and SMIDR_EL1
+ */
+ #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
+ HCR_BSU_IS | HCR_FB | HCR_TACR | \
+ HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
+- HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3)
++ HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1)
+ #define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
+ #define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
+ #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
+diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
+index 42791971f7588..05c6f3c9bce25 100644
+--- a/arch/arm64/kvm/sys_regs.c
++++ b/arch/arm64/kvm/sys_regs.c
+@@ -2323,6 +2323,94 @@ static unsigned int s1poe_visibility(const struct kvm_vcpu *vcpu,
+ return REG_HIDDEN;
+ }
+
++/*
++ * For historical (ahem ABI) reasons, KVM treated MIDR_EL1, REVIDR_EL1, and
++ * AIDR_EL1 as "invariant" registers, meaning userspace cannot change them.
++ * The values made visible to userspace were the register values of the boot
++ * CPU.
++ *
++ * At the same time, reads from these registers at EL1 previously were not
++ * trapped, allowing the guest to read the actual hardware value. On big-little
++ * machines, this means the VM can see different values depending on where a
++ * given vCPU got scheduled.
++ *
++ * These registers are now trapped as collateral damage from SME, and what
++ * follows attempts to give a user / guest view consistent with the existing
++ * ABI.
++ */
++static bool access_imp_id_reg(struct kvm_vcpu *vcpu,
++ struct sys_reg_params *p,
++ const struct sys_reg_desc *r)
++{
++ if (p->is_write)
++ return write_to_read_only(vcpu, p, r);
++
++ switch (reg_to_encoding(r)) {
++ case SYS_REVIDR_EL1:
++ p->regval = read_sysreg(revidr_el1);
++ break;
++ case SYS_AIDR_EL1:
++ p->regval = read_sysreg(aidr_el1);
++ break;
++ default:
++ WARN_ON_ONCE(1);
++ }
++
++ return true;
++}
++
++static u64 __ro_after_init boot_cpu_midr_val;
++static u64 __ro_after_init boot_cpu_revidr_val;
++static u64 __ro_after_init boot_cpu_aidr_val;
++
++static void init_imp_id_regs(void)
++{
++ boot_cpu_midr_val = read_sysreg(midr_el1);
++ boot_cpu_revidr_val = read_sysreg(revidr_el1);
++ boot_cpu_aidr_val = read_sysreg(aidr_el1);
++}
++
++static int get_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
++ u64 *val)
++{
++ switch (reg_to_encoding(r)) {
++ case SYS_MIDR_EL1:
++ *val = boot_cpu_midr_val;
++ break;
++ case SYS_REVIDR_EL1:
++ *val = boot_cpu_revidr_val;
++ break;
++ case SYS_AIDR_EL1:
++ *val = boot_cpu_aidr_val;
++ break;
++ default:
++ WARN_ON_ONCE(1);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int set_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
++ u64 val)
++{
++ u64 expected;
++ int ret;
++
++ ret = get_imp_id_reg(vcpu, r, &expected);
++ if (ret)
++ return ret;
++
++ return (expected == val) ? 0 : -EINVAL;
++}
++
++#define IMPLEMENTATION_ID(reg) { \
++ SYS_DESC(SYS_##reg), \
++ .access = access_imp_id_reg, \
++ .get_user = get_imp_id_reg, \
++ .set_user = set_imp_id_reg, \
++}
++
+ /*
+ * Architected system registers.
+ * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
+@@ -2371,7 +2459,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
+
+ { SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 },
+
++ IMPLEMENTATION_ID(MIDR_EL1),
+ { SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
++ IMPLEMENTATION_ID(REVIDR_EL1),
+
+ /*
+ * ID regs: all ID_SANITISED() entries here must have corresponding
+@@ -2648,6 +2738,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
+ .set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
+ { SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
+ { SYS_DESC(SYS_SMIDR_EL1), undef_access },
++ IMPLEMENTATION_ID(AIDR_EL1),
+ { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
+ ID_WRITABLE(CTR_EL0, CTR_EL0_DIC_MASK |
+ CTR_EL0_IDC_MASK |
+@@ -4060,9 +4151,13 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu)
+ * Certain AArch32 ID registers are handled by rerouting to the AArch64
+ * system register table. Registers in the ID range where CRm=0 are
+ * excluded from this scheme as they do not trivially map into AArch64
+- * system register encodings.
++ * system register encodings, except for AIDR/REVIDR.
+ */
+- if (params.Op1 == 0 && params.CRn == 0 && params.CRm)
++ if (params.Op1 == 0 && params.CRn == 0 &&
++ (params.CRm || params.Op2 == 6 /* REVIDR */))
++ return kvm_emulate_cp15_id_reg(vcpu, &params);
++ if (params.Op1 == 1 && params.CRn == 0 &&
++ params.CRm == 0 && params.Op2 == 7 /* AIDR */)
+ return kvm_emulate_cp15_id_reg(vcpu, &params);
+
+ return kvm_handle_cp_32(vcpu, &params, cp15_regs, ARRAY_SIZE(cp15_regs));
+@@ -4363,65 +4458,6 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id,
+ return r;
+ }
+
+-/*
+- * These are the invariant sys_reg registers: we let the guest see the
+- * host versions of these, so they're part of the guest state.
+- *
+- * A future CPU may provide a mechanism to present different values to
+- * the guest, or a future kvm may trap them.
+- */
+-
+-#define FUNCTION_INVARIANT(reg) \
+- static u64 reset_##reg(struct kvm_vcpu *v, \
+- const struct sys_reg_desc *r) \
+- { \
+- ((struct sys_reg_desc *)r)->val = read_sysreg(reg); \
+- return ((struct sys_reg_desc *)r)->val; \
+- }
+-
+-FUNCTION_INVARIANT(midr_el1)
+-FUNCTION_INVARIANT(revidr_el1)
+-FUNCTION_INVARIANT(aidr_el1)
+-
+-/* ->val is filled in by kvm_sys_reg_table_init() */
+-static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = {
+- { SYS_DESC(SYS_MIDR_EL1), NULL, reset_midr_el1 },
+- { SYS_DESC(SYS_REVIDR_EL1), NULL, reset_revidr_el1 },
+- { SYS_DESC(SYS_AIDR_EL1), NULL, reset_aidr_el1 },
+-};
+-
+-static int get_invariant_sys_reg(u64 id, u64 __user *uaddr)
+-{
+- const struct sys_reg_desc *r;
+-
+- r = get_reg_by_id(id, invariant_sys_regs,
+- ARRAY_SIZE(invariant_sys_regs));
+- if (!r)
+- return -ENOENT;
+-
+- return put_user(r->val, uaddr);
+-}
+-
+-static int set_invariant_sys_reg(u64 id, u64 __user *uaddr)
+-{
+- const struct sys_reg_desc *r;
+- u64 val;
+-
+- r = get_reg_by_id(id, invariant_sys_regs,
+- ARRAY_SIZE(invariant_sys_regs));
+- if (!r)
+- return -ENOENT;
+-
+- if (get_user(val, uaddr))
+- return -EFAULT;
+-
+- /* This is what we mean by invariant: you can't change it. */
+- if (r->val != val)
+- return -EINVAL;
+-
+- return 0;
+-}
+-
+ static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
+ {
+ u32 val;
+@@ -4503,15 +4539,10 @@ int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
+ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+ {
+ void __user *uaddr = (void __user *)(unsigned long)reg->addr;
+- int err;
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+ return demux_c15_get(vcpu, reg->id, uaddr);
+
+- err = get_invariant_sys_reg(reg->id, uaddr);
+- if (err != -ENOENT)
+- return err;
+-
+ return kvm_sys_reg_get_user(vcpu, reg,
+ sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+ }
+@@ -4547,15 +4578,10 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
+ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+ {
+ void __user *uaddr = (void __user *)(unsigned long)reg->addr;
+- int err;
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+ return demux_c15_set(vcpu, reg->id, uaddr);
+
+- err = set_invariant_sys_reg(reg->id, uaddr);
+- if (err != -ENOENT)
+- return err;
+-
+ return kvm_sys_reg_set_user(vcpu, reg,
+ sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+ }
+@@ -4644,23 +4670,14 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
+
+ unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
+ {
+- return ARRAY_SIZE(invariant_sys_regs)
+- + num_demux_regs()
++ return num_demux_regs()
+ + walk_sys_regs(vcpu, (u64 __user *)NULL);
+ }
+
+ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+ {
+- unsigned int i;
+ int err;
+
+- /* Then give them all the invariant registers' indices. */
+- for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) {
+- if (put_user(sys_reg_to_index(&invariant_sys_regs[i]), uindices))
+- return -EFAULT;
+- uindices++;
+- }
+-
+ err = walk_sys_regs(vcpu, uindices);
+ if (err < 0)
+ return err;
+@@ -4878,15 +4895,12 @@ int __init kvm_sys_reg_table_init(void)
+ valid &= check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs), true);
+ valid &= check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs), true);
+ valid &= check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs), true);
+- valid &= check_sysreg_table(invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs), false);
+ valid &= check_sysreg_table(sys_insn_descs, ARRAY_SIZE(sys_insn_descs), false);
+
+ if (!valid)
+ return -EINVAL;
+
+- /* We abuse the reset function to overwrite the table itself. */
+- for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
+- invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]);
++ init_imp_id_regs();
+
+ ret = populate_nv_trap_config();
+
+--
+2.39.5
+
diff --git a/queue-6.12/loongarch-set-hugetlb-mmap-base-address-aligned-with.patch b/queue-6.12/loongarch-set-hugetlb-mmap-base-address-aligned-with.patch
new file mode 100644
index 0000000000..d96a803c3c
--- /dev/null
+++ b/queue-6.12/loongarch-set-hugetlb-mmap-base-address-aligned-with.patch
@@ -0,0 +1,88 @@
+From ca3c89c940d1d5db28dc90f598ba763ce04399a1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 8 Mar 2025 13:51:32 +0800
+Subject: LoongArch: Set hugetlb mmap base address aligned with pmd size
+
+From: Bibo Mao <maobibo@loongson.cn>
+
+[ Upstream commit 3109d5ff484b7bc7b955f166974c6776d91f247b ]
+
+With ltp test case "testcases/bin/hugefork02", there is a dmesg error
+report message such as:
+
+ kernel BUG at mm/hugetlb.c:5550!
+ Oops - BUG[#1]:
+ CPU: 0 UID: 0 PID: 1517 Comm: hugefork02 Not tainted 6.14.0-rc2+ #241
+ Hardware name: QEMU QEMU Virtual Machine, BIOS unknown 2/2/2022
+ pc 90000000004eaf1c ra 9000000000485538 tp 900000010edbc000 sp 900000010edbf940
+ a0 900000010edbfb00 a1 9000000108d20280 a2 00007fffe9474000 a3 00007ffff3474000
+ a4 0000000000000000 a5 0000000000000003 a6 00000000003cadd3 a7 0000000000000000
+ t0 0000000001ffffff t1 0000000001474000 t2 900000010ecd7900 t3 00007fffe9474000
+ t4 00007fffe9474000 t5 0000000000000040 t6 900000010edbfb00 t7 0000000000000001
+ t8 0000000000000005 u0 90000000004849d0 s9 900000010edbfa00 s0 9000000108d20280
+ s1 00007fffe9474000 s2 0000000002000000 s3 9000000108d20280 s4 9000000002b38b10
+ s5 900000010edbfb00 s6 00007ffff3474000 s7 0000000000000406 s8 900000010edbfa08
+ ra: 9000000000485538 unmap_vmas+0x130/0x218
+ ERA: 90000000004eaf1c __unmap_hugepage_range+0x6f4/0x7d0
+ PRMD: 00000004 (PPLV0 +PIE -PWE)
+ EUEN: 00000007 (+FPE +SXE +ASXE -BTE)
+ ECFG: 00071c1d (LIE=0,2-4,10-12 VS=7)
+ ESTAT: 000c0000 [BRK] (IS= ECode=12 EsubCode=0)
+ PRID: 0014c010 (Loongson-64bit, Loongson-3A5000)
+ Process hugefork02 (pid: 1517, threadinfo=00000000a670eaf4, task=000000007a95fc64)
+ Call Trace:
+ [<90000000004eaf1c>] __unmap_hugepage_range+0x6f4/0x7d0
+ [<9000000000485534>] unmap_vmas+0x12c/0x218
+ [<9000000000494068>] exit_mmap+0xe0/0x308
+ [<900000000025fdc4>] mmput+0x74/0x180
+ [<900000000026a284>] do_exit+0x294/0x898
+ [<900000000026aa30>] do_group_exit+0x30/0x98
+ [<900000000027bed4>] get_signal+0x83c/0x868
+ [<90000000002457b4>] arch_do_signal_or_restart+0x54/0xfa0
+ [<90000000015795e8>] irqentry_exit_to_user_mode+0xb8/0x138
+ [<90000000002572d0>] tlb_do_page_fault_1+0x114/0x1b4
+
+The problem is that base address allocated from hugetlbfs is not aligned
+with pmd size. Here add a checking for hugetlbfs and align base address
+with pmd size. After this patch the test case "testcases/bin/hugefork02"
+passes to run.
+
+This is similar to the commit 7f24cbc9c4d42db8a3c8484d1 ("mm/mmap: teach
+generic_get_unmapped_area{_topdown} to handle hugetlb mappings").
+
+Cc: stable@vger.kernel.org # 6.13+
+Signed-off-by: Bibo Mao <maobibo@loongson.cn>
+Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/loongarch/mm/mmap.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/arch/loongarch/mm/mmap.c b/arch/loongarch/mm/mmap.c
+index 914e82ff3f656..1df9e99582cc6 100644
+--- a/arch/loongarch/mm/mmap.c
++++ b/arch/loongarch/mm/mmap.c
+@@ -3,6 +3,7 @@
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+ #include <linux/export.h>
++#include <linux/hugetlb.h>
+ #include <linux/io.h>
+ #include <linux/kfence.h>
+ #include <linux/memblock.h>
+@@ -63,8 +64,11 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp,
+ }
+
+ info.length = len;
+- info.align_mask = do_color_align ? (PAGE_MASK & SHM_ALIGN_MASK) : 0;
+ info.align_offset = pgoff << PAGE_SHIFT;
++ if (filp && is_file_hugepages(filp))
++ info.align_mask = huge_page_mask_align(filp);
++ else
++ info.align_mask = do_color_align ? (PAGE_MASK & SHM_ALIGN_MASK) : 0;
+
+ if (dir == DOWN) {
+ info.flags = VM_UNMAPPED_AREA_TOPDOWN;
+--
+2.39.5
+
diff --git a/queue-6.12/net-stmmac-fix-accessing-freed-irq-affinity_hint.patch b/queue-6.12/net-stmmac-fix-accessing-freed-irq-affinity_hint.patch
new file mode 100644
index 0000000000..09d2b3fa49
--- /dev/null
+++ b/queue-6.12/net-stmmac-fix-accessing-freed-irq-affinity_hint.patch
@@ -0,0 +1,63 @@
+From e82347444599c944993255de39c51a8b8a892f5d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Mar 2025 11:24:23 +0800
+Subject: net: stmmac: Fix accessing freed irq affinity_hint
+
+From: Qingfang Deng <dqfext@gmail.com>
+
+[ Upstream commit c60d101a226f18e9a8f01bb4c6ca2b47dfcb15ef ]
+
+The cpumask should not be a local variable, since its pointer is saved
+to irq_desc and may be accessed from procfs.
+To fix it, use the persistent mask cpumask_of(cpu#).
+
+Cc: stable@vger.kernel.org
+Fixes: 8deec94c6040 ("net: stmmac: set IRQ affinity hint for multi MSI vectors")
+Signed-off-by: Qingfang Deng <dqfext@gmail.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20250318032424.112067-1-dqfext@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index 0250c5cb28ff2..36328298dc9b8 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -3603,7 +3603,6 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
+ {
+ struct stmmac_priv *priv = netdev_priv(dev);
+ enum request_irq_err irq_err;
+- cpumask_t cpu_mask;
+ int irq_idx = 0;
+ char *int_name;
+ int ret;
+@@ -3732,9 +3731,8 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
+ irq_idx = i;
+ goto irq_error;
+ }
+- cpumask_clear(&cpu_mask);
+- cpumask_set_cpu(i % num_online_cpus(), &cpu_mask);
+- irq_set_affinity_hint(priv->rx_irq[i], &cpu_mask);
++ irq_set_affinity_hint(priv->rx_irq[i],
++ cpumask_of(i % num_online_cpus()));
+ }
+
+ /* Request Tx MSI irq */
+@@ -3757,9 +3755,8 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
+ irq_idx = i;
+ goto irq_error;
+ }
+- cpumask_clear(&cpu_mask);
+- cpumask_set_cpu(i % num_online_cpus(), &cpu_mask);
+- irq_set_affinity_hint(priv->tx_irq[i], &cpu_mask);
++ irq_set_affinity_hint(priv->tx_irq[i],
++ cpumask_of(i % num_online_cpus()));
+ }
+
+ return 0;
+--
+2.39.5
+
diff --git a/queue-6.12/riscv-atomic-do-proper-sign-extension-also-for-unsig.patch b/queue-6.12/riscv-atomic-do-proper-sign-extension-also-for-unsig.patch
new file mode 100644
index 0000000000..829225fd10
--- /dev/null
+++ b/queue-6.12/riscv-atomic-do-proper-sign-extension-also-for-unsig.patch
@@ -0,0 +1,46 @@
+From b57b1eac9edb010056dd04b311ac8b57b6aade8e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Jul 2025 18:01:44 -0400
+Subject: riscv/atomic: Do proper sign extension also for unsigned in
+ arch_cmpxchg
+
+[ Upstream commit 1898300abf3508bca152e65b36cce5bf93d7e63e ]
+
+Sign extend also an unsigned compare value to match what lr.w is doing.
+Otherwise try_cmpxchg may spuriously return true when used on a u32 value
+that has the sign bit set, as it happens often in inode_set_ctime_current.
+
+Do this in three conversion steps. The first conversion to long is needed
+to avoid a -Wpointer-to-int-cast warning when arch_cmpxchg is used with a
+pointer type. Then convert to int and back to long to always sign extend
+the 32-bit value to 64-bit.
+
+Fixes: 6c58f25e6938 ("riscv/atomic: Fix sign extension for RV64I")
+Signed-off-by: Andreas Schwab <schwab@suse.de>
+Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
+Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
+Tested-by: Xi Ruoyao <xry111@xry111.site>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/mvmed0k4prh.fsf@suse.de
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/include/asm/cmpxchg.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h
+index ebbce134917cc..6efa95ad033ab 100644
+--- a/arch/riscv/include/asm/cmpxchg.h
++++ b/arch/riscv/include/asm/cmpxchg.h
+@@ -169,7 +169,7 @@
+ break; \
+ case 4: \
+ __arch_cmpxchg(".w", ".w" sc_sfx, prepend, append, \
+- __ret, __ptr, (long), __old, __new); \
++ __ret, __ptr, (long)(int)(long), __old, __new); \
+ break; \
+ case 8: \
+ __arch_cmpxchg(".d", ".d" sc_sfx, prepend, append, \
+--
+2.39.5
+
diff --git a/queue-6.12/series b/queue-6.12/series
index fd8002791f..0cbce2df08 100644
--- a/queue-6.12/series
+++ b/queue-6.12/series
@@ -201,3 +201,29 @@ mm-vma-reset-vma-iterator-on-commit_merge-oom-failure.patch
r8169-add-support-for-rtl8125d.patch
net-phy-realtek-merge-the-drivers-for-internal-nbase-t-phy-s.patch
net-phy-realtek-add-rtl8125d-internal-phy.patch
+btrfs-do-proper-folio-cleanup-when-cow_file_range-fa.patch
+iio-dac-ad3552r-changes-to-use-field_prep.patch
+iio-dac-ad3552r-extract-common-code-no-changes-in-be.patch
+iio-dac-ad3552r-common-fix-ad3541-2r-ranges.patch
+drm-xe-carve-out-wopcm-portion-from-the-stolen-memor.patch
+usb-typec-tcpm-pssourceofftimer-timeout-in-pr_swap-e.patch
+drm-msm-dp-account-for-widebus-and-yuv420-during-mod.patch
+drm-fbdev-dma-add-shadow-buffering-for-deferred-i-o.patch
+btrfs-skip-inodes-without-loaded-extent-maps-when-sh.patch
+btrfs-make-the-extent-map-shrinker-run-asynchronousl.patch
+btrfs-do-regular-iput-instead-of-delayed-iput-during.patch
+riscv-atomic-do-proper-sign-extension-also-for-unsig.patch
+loongarch-set-hugetlb-mmap-base-address-aligned-with.patch
+arm64-dts-rockchip-add-avdd-hdmi-supplies-to-rockpro.patch
+alsa-hda-realtek-bass-speaker-fixup-for-asus-um5606k.patch
+drm-amdkfd-remove-gfx-12-trap-handler-page-size-cap.patch
+drm-amdkfd-fix-instruction-hazard-in-gfx12-trap-hand.patch
+kvm-arm64-set-hcr_el2.tid1-unconditionally.patch
+net-stmmac-fix-accessing-freed-irq-affinity_hint.patch
+spi-spi-mem-extend-spi-mem-operations-with-a-per-ope.patch
+spi-spi-mem-add-a-new-controller-capability.patch
+spi-fsl-qspi-support-per-spi-mem-operation-frequency.patch
+spi-fsl-qspi-use-devm-function-instead-of-driver-rem.patch
+btrfs-zoned-fix-extent-range-end-unlock-in-cow_file_.patch
+btrfs-fix-use-after-free-on-inode-when-scanning-root.patch
+spi-fsl-qspi-fix-double-cleanup-in-probe-error-path.patch
diff --git a/queue-6.12/spi-fsl-qspi-fix-double-cleanup-in-probe-error-path.patch b/queue-6.12/spi-fsl-qspi-fix-double-cleanup-in-probe-error-path.patch
new file mode 100644
index 0000000000..99d418b99f
--- /dev/null
+++ b/queue-6.12/spi-fsl-qspi-fix-double-cleanup-in-probe-error-path.patch
@@ -0,0 +1,61 @@
+From 83ec22b65ff203f224c9406a773026b6101f9571 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Apr 2025 14:56:09 +0800
+Subject: spi: fsl-qspi: Fix double cleanup in probe error path
+
+From: Kevin Hao <haokexin@gmail.com>
+
+[ Upstream commit 5d07ab2a7fa1305e429d9221716582f290b58078 ]
+
+Commit 40369bfe717e ("spi: fsl-qspi: use devm function instead of driver
+remove") introduced managed cleanup via fsl_qspi_cleanup(), but
+incorrectly retain manual cleanup in two scenarios:
+
+- On devm_add_action_or_reset() failure, the function automatically call
+ fsl_qspi_cleanup(). However, the current code still jumps to
+ err_destroy_mutex, repeating cleanup.
+
+- After the fsl_qspi_cleanup() action is added successfully, there is no
+ need to manually perform the cleanup in the subsequent error path.
+ However, the current code still jumps to err_destroy_mutex on spi
+ controller failure, repeating cleanup.
+
+Skip redundant manual cleanup calls to fix these issues.
+
+Cc: stable@vger.kernel.org
+Fixes: 40369bfe717e ("spi: fsl-qspi: use devm function instead of driver remove")
+Signed-off-by: Kevin Hao <haokexin@gmail.com>
+Link: https://patch.msgid.link/20250410-spi-v1-1-56e867cc19cf@gmail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-fsl-qspi.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
+index 5c59fddb32c1b..2f54dc09d11b1 100644
+--- a/drivers/spi/spi-fsl-qspi.c
++++ b/drivers/spi/spi-fsl-qspi.c
+@@ -949,17 +949,14 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+
+ ret = devm_add_action_or_reset(dev, fsl_qspi_cleanup, q);
+ if (ret)
+- goto err_destroy_mutex;
++ goto err_put_ctrl;
+
+ ret = devm_spi_register_controller(dev, ctlr);
+ if (ret)
+- goto err_destroy_mutex;
++ goto err_put_ctrl;
+
+ return 0;
+
+-err_destroy_mutex:
+- mutex_destroy(&q->lock);
+-
+ err_disable_clk:
+ fsl_qspi_clk_disable_unprep(q);
+
+--
+2.39.5
+
diff --git a/queue-6.12/spi-fsl-qspi-support-per-spi-mem-operation-frequency.patch b/queue-6.12/spi-fsl-qspi-support-per-spi-mem-operation-frequency.patch
new file mode 100644
index 0000000000..5bc46487b3
--- /dev/null
+++ b/queue-6.12/spi-fsl-qspi-support-per-spi-mem-operation-frequency.patch
@@ -0,0 +1,76 @@
+From 0eb0997cc79b65fff30e73b5572d5633cf7752f4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Dec 2024 18:05:53 +0100
+Subject: spi: fsl-qspi: Support per spi-mem operation frequency switches
+
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+
+[ Upstream commit 2438db5253eb17a7c0ccb15aea4252a150dda057 ]
+
+Every ->exec_op() call correctly configures the spi bus speed to the
+maximum allowed frequency for the memory using the constant spi default
+parameter. Since we can now have per-operation constraints, let's use
+the value that comes from the spi-mem operation structure instead. In
+case there is no specific limitation for this operation, the default spi
+device value will be given anyway.
+
+The per-operation frequency capability is thus advertised to the spi-mem
+core.
+
+Cc: Han Xu <han.xu@nxp.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://patch.msgid.link/20241224-winbond-6-11-rc1-quad-support-v2-8-ad218dbc406f@bootlin.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-fsl-qspi.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
+index 79bac30e79af6..ce86f44b0e93f 100644
+--- a/drivers/spi/spi-fsl-qspi.c
++++ b/drivers/spi/spi-fsl-qspi.c
+@@ -522,9 +522,10 @@ static void fsl_qspi_invalidate(struct fsl_qspi *q)
+ qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
+ }
+
+-static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi)
++static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi,
++ const struct spi_mem_op *op)
+ {
+- unsigned long rate = spi->max_speed_hz;
++ unsigned long rate = op->max_freq;
+ int ret;
+
+ if (q->selected == spi_get_chipselect(spi, 0))
+@@ -652,7 +653,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+ fsl_qspi_readl_poll_tout(q, base + QUADSPI_SR, (QUADSPI_SR_IP_ACC_MASK |
+ QUADSPI_SR_AHB_ACC_MASK), 10, 1000);
+
+- fsl_qspi_select_mem(q, mem->spi);
++ fsl_qspi_select_mem(q, mem->spi, op);
+
+ if (needs_amba_base_offset(q))
+ addr_offset = q->memmap_phy;
+@@ -839,6 +840,10 @@ static const struct spi_controller_mem_ops fsl_qspi_mem_ops = {
+ .get_name = fsl_qspi_get_name,
+ };
+
++static const struct spi_controller_mem_caps fsl_qspi_mem_caps = {
++ .per_op_freq = true,
++};
++
+ static int fsl_qspi_probe(struct platform_device *pdev)
+ {
+ struct spi_controller *ctlr;
+@@ -923,6 +928,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ ctlr->bus_num = -1;
+ ctlr->num_chipselect = 4;
+ ctlr->mem_ops = &fsl_qspi_mem_ops;
++ ctlr->mem_caps = &fsl_qspi_mem_caps;
+
+ fsl_qspi_default_setup(q);
+
+--
+2.39.5
+
diff --git a/queue-6.12/spi-fsl-qspi-use-devm-function-instead-of-driver-rem.patch b/queue-6.12/spi-fsl-qspi-use-devm-function-instead-of-driver-rem.patch
new file mode 100644
index 0000000000..9217c93921
--- /dev/null
+++ b/queue-6.12/spi-fsl-qspi-use-devm-function-instead-of-driver-rem.patch
@@ -0,0 +1,96 @@
+From 201bd9e3cb2e7ccdd87022ea46227dd746514823 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Mar 2025 17:41:51 -0500
+Subject: spi: fsl-qspi: use devm function instead of driver remove
+
+From: Han Xu <han.xu@nxp.com>
+
+[ Upstream commit 40369bfe717e96e26650eeecfa5a6363563df6e4 ]
+
+Driver use devm APIs to manage clk/irq/resources and register the spi
+controller, but the legacy remove function will be called first during
+device detach and trigger kernel panic. Drop the remove function and use
+devm_add_action_or_reset() for driver cleanup to ensure the release
+sequence.
+
+Trigger kernel panic on i.MX8MQ by
+echo 30bb0000.spi >/sys/bus/platform/drivers/fsl-quadspi/unbind
+
+Cc: stable@vger.kernel.org
+Fixes: 8fcb830a00f0 ("spi: spi-fsl-qspi: use devm_spi_register_controller")
+Reported-by: Kevin Hao <haokexin@gmail.com>
+Signed-off-by: Han Xu <han.xu@nxp.com>
+Reviewed-by: Frank Li <Frank.Li@nxp.com>
+Link: https://patch.msgid.link/20250326224152.2147099-1-han.xu@nxp.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-fsl-qspi.c | 31 +++++++++++++++++--------------
+ 1 file changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
+index ce86f44b0e93f..5c59fddb32c1b 100644
+--- a/drivers/spi/spi-fsl-qspi.c
++++ b/drivers/spi/spi-fsl-qspi.c
+@@ -844,6 +844,19 @@ static const struct spi_controller_mem_caps fsl_qspi_mem_caps = {
+ .per_op_freq = true,
+ };
+
++static void fsl_qspi_cleanup(void *data)
++{
++ struct fsl_qspi *q = data;
++
++ /* disable the hardware */
++ qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
++ qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
++
++ fsl_qspi_clk_disable_unprep(q);
++
++ mutex_destroy(&q->lock);
++}
++
+ static int fsl_qspi_probe(struct platform_device *pdev)
+ {
+ struct spi_controller *ctlr;
+@@ -934,6 +947,10 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+
+ ctlr->dev.of_node = np;
+
++ ret = devm_add_action_or_reset(dev, fsl_qspi_cleanup, q);
++ if (ret)
++ goto err_destroy_mutex;
++
+ ret = devm_spi_register_controller(dev, ctlr);
+ if (ret)
+ goto err_destroy_mutex;
+@@ -953,19 +970,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
+ return ret;
+ }
+
+-static void fsl_qspi_remove(struct platform_device *pdev)
+-{
+- struct fsl_qspi *q = platform_get_drvdata(pdev);
+-
+- /* disable the hardware */
+- qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+- qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
+-
+- fsl_qspi_clk_disable_unprep(q);
+-
+- mutex_destroy(&q->lock);
+-}
+-
+ static int fsl_qspi_suspend(struct device *dev)
+ {
+ return 0;
+@@ -1003,7 +1007,6 @@ static struct platform_driver fsl_qspi_driver = {
+ .pm = &fsl_qspi_pm_ops,
+ },
+ .probe = fsl_qspi_probe,
+- .remove_new = fsl_qspi_remove,
+ };
+ module_platform_driver(fsl_qspi_driver);
+
+--
+2.39.5
+
diff --git a/queue-6.12/spi-spi-mem-add-a-new-controller-capability.patch b/queue-6.12/spi-spi-mem-add-a-new-controller-capability.patch
new file mode 100644
index 0000000000..bbbc1c1bdc
--- /dev/null
+++ b/queue-6.12/spi-spi-mem-add-a-new-controller-capability.patch
@@ -0,0 +1,71 @@
+From 16d2efcbbac33cd7d1be2d934b9bfb3f24425544 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Dec 2024 18:05:47 +0100
+Subject: spi: spi-mem: Add a new controller capability
+
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+
+[ Upstream commit 1248c9b8d54120950fda10fbeb98fb8932b4d45c ]
+
+There are spi devices with multiple frequency limitations depending on
+the invoked command. We probably do not want to afford running at the
+lowest supported frequency all the time, so if we want to get the most
+of our hardware, we need to allow per-operation frequency limitations.
+
+Among all the SPI memory controllers, I believe all are capable of
+changing the spi frequency on the fly. Some of the drivers do not make
+any frequency setup though. And some others will derive a per chip
+prescaler value which will be used forever.
+
+Actually changing the frequency on the fly is something new in Linux, so
+we need to carefully flag the drivers which do and do not support it. A
+controller capability is created for that, and the presence for this
+capability will always be checked before accepting such pattern.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Reviewed-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Link: https://patch.msgid.link/20241224-winbond-6-11-rc1-quad-support-v2-2-ad218dbc406f@bootlin.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/spi/spi-mem.c | 6 ++++++
+ include/linux/spi/spi-mem.h | 2 ++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
+index f8b598ba962d9..d0ae20d433d61 100644
+--- a/drivers/spi/spi-mem.c
++++ b/drivers/spi/spi-mem.c
+@@ -188,6 +188,12 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
+ op->max_freq < mem->spi->controller->min_speed_hz)
+ return false;
+
++ if (op->max_freq &&
++ op->max_freq < mem->spi->max_speed_hz) {
++ if (!spi_mem_controller_is_capable(ctlr, per_op_freq))
++ return false;
++ }
++
+ return spi_mem_check_buswidth(mem, op);
+ }
+ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
+diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
+index 44b7ecee0e74c..0f00d74beb24c 100644
+--- a/include/linux/spi/spi-mem.h
++++ b/include/linux/spi/spi-mem.h
+@@ -306,10 +306,12 @@ struct spi_controller_mem_ops {
+ * struct spi_controller_mem_caps - SPI memory controller capabilities
+ * @dtr: Supports DTR operations
+ * @ecc: Supports operations with error correction
++ * @per_op_freq: Supports per operation frequency switching
+ */
+ struct spi_controller_mem_caps {
+ bool dtr;
+ bool ecc;
++ bool per_op_freq;
+ };
+
+ #define spi_mem_controller_is_capable(ctlr, cap) \
+--
+2.39.5
+
diff --git a/queue-6.12/spi-spi-mem-extend-spi-mem-operations-with-a-per-ope.patch b/queue-6.12/spi-spi-mem-extend-spi-mem-operations-with-a-per-ope.patch
new file mode 100644
index 0000000000..5831735a27
--- /dev/null
+++ b/queue-6.12/spi-spi-mem-extend-spi-mem-operations-with-a-per-ope.patch
@@ -0,0 +1,220 @@
+From 00311c92a5496aed8892149e05fc9b8d66c78b36 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Dec 2024 18:05:46 +0100
+Subject: spi: spi-mem: Extend spi-mem operations with a per-operation maximum
+ frequency
+
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+
+[ Upstream commit 0fefeade90e74bc8f40ab0e460f483565c492e28 ]
+
+In the spi subsystem, the bus frequency is derived as follows:
+- the controller may expose a minimum and maximum operating frequency
+- the hardware description, through the spi peripheral properties,
+ advise what is the maximum acceptable frequency from a device/wiring
+ point of view.
+Transfers must be observed at a frequency which fits both (so in
+practice, the lowest maximum).
+
+Actually, this second point mixes two information and already takes the
+lowest frequency among:
+- what the spi device is capable of (what is written in the component
+ datasheet)
+- what the wiring allows (electromagnetic sensibility, crossovers,
+ terminations, antenna effect, etc).
+
+This logic works until spi devices are no longer capable of sustaining
+their highest frequency regardless of the operation. Spi memories are
+typically subject to such variation. Some devices are capable of
+spitting their internally stored data (essentially in read mode) at a
+very fast rate, typically up to 166MHz on Winbond SPI-NAND chips, using
+"fast" commands. However, some of the low-end operations, such as
+regular page read-from-cache commands, are more limited and can only be
+executed at 54MHz at most. This is currently a problem in the SPI-NAND
+subsystem. Another situation, even if not yet supported, will be with
+DTR commands, when the data is latched on both edges of the clock. The
+same chips as mentioned previously are in this case limited to
+80MHz. Yet another example might be continuous reads, which, under
+certain circumstances, can also run at most at 104 or 120MHz.
+
+As a matter of fact, the "one frequency per chip" policy is outdated and
+more fine grain configuration is needed: we need to allow per-operation
+frequency limitations. So far, all datasheets I encountered advertise a
+maximum default frequency, which need to be lowered for certain specific
+operations. So based on the current infrastructure, we can still expect
+firmware (device trees in general) to continued advertising the same
+maximum speed which is a mix between the PCB limitations and the chip
+maximum capability, and expect per-operation lower frequencies when this
+is relevant.
+
+Add a `struct spi_mem_op` member to carry this information. Not
+providing this field explicitly from upper layers means that there is no
+further constraint and the default spi device maximum speed will be
+carried instead. The SPI_MEM_OP() macro is also expanded with an
+optional frequency argument, because virtually all operations can be
+subject to such a limitation, and this will allow for a smooth and
+discrete transition.
+
+For controller drivers which do not implement the spi-mem interface, the
+per-transfer speed is also set acordingly to a lower (than the maximum
+default) speed when relevant.
+
+Acked-by: Pratyush Yadav <pratyush@kernel.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://patch.msgid.link/20241224-winbond-6-11-rc1-quad-support-v2-1-ad218dbc406f@bootlin.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mtd/nand/spi/core.c | 2 ++
+ drivers/spi/spi-mem.c | 28 ++++++++++++++++++++++++++++
+ include/linux/spi/spi-mem.h | 12 +++++++++++-
+ 3 files changed, 41 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
+index 4d76f9f71a0e9..075f513157603 100644
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -1214,6 +1214,8 @@ spinand_select_op_variant(struct spinand_device *spinand,
+ if (ret)
+ break;
+
++ spi_mem_adjust_op_freq(spinand->spimem, &op);
++
+ if (!spi_mem_supports_op(spinand->spimem, &op))
+ break;
+
+diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
+index 17b8baf749e6a..f8b598ba962d9 100644
+--- a/drivers/spi/spi-mem.c
++++ b/drivers/spi/spi-mem.c
+@@ -184,6 +184,10 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
+ return false;
+ }
+
++ if (op->max_freq && mem->spi->controller->min_speed_hz &&
++ op->max_freq < mem->spi->controller->min_speed_hz)
++ return false;
++
+ return spi_mem_check_buswidth(mem, op);
+ }
+ EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
+@@ -361,6 +365,9 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+ u8 *tmpbuf;
+ int ret;
+
++ /* Make sure the operation frequency is correct before going futher */
++ spi_mem_adjust_op_freq(mem, (struct spi_mem_op *)op);
++
+ ret = spi_mem_check_op(op);
+ if (ret)
+ return ret;
+@@ -407,6 +414,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+ xfers[xferpos].tx_buf = tmpbuf;
+ xfers[xferpos].len = op->cmd.nbytes;
+ xfers[xferpos].tx_nbits = op->cmd.buswidth;
++ xfers[xferpos].speed_hz = op->max_freq;
+ spi_message_add_tail(&xfers[xferpos], &msg);
+ xferpos++;
+ totalxferlen++;
+@@ -421,6 +429,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+ xfers[xferpos].tx_buf = tmpbuf + 1;
+ xfers[xferpos].len = op->addr.nbytes;
+ xfers[xferpos].tx_nbits = op->addr.buswidth;
++ xfers[xferpos].speed_hz = op->max_freq;
+ spi_message_add_tail(&xfers[xferpos], &msg);
+ xferpos++;
+ totalxferlen += op->addr.nbytes;
+@@ -432,6 +441,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+ xfers[xferpos].len = op->dummy.nbytes;
+ xfers[xferpos].tx_nbits = op->dummy.buswidth;
+ xfers[xferpos].dummy_data = 1;
++ xfers[xferpos].speed_hz = op->max_freq;
+ spi_message_add_tail(&xfers[xferpos], &msg);
+ xferpos++;
+ totalxferlen += op->dummy.nbytes;
+@@ -447,6 +457,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+ }
+
+ xfers[xferpos].len = op->data.nbytes;
++ xfers[xferpos].speed_hz = op->max_freq;
+ spi_message_add_tail(&xfers[xferpos], &msg);
+ xferpos++;
+ totalxferlen += op->data.nbytes;
+@@ -525,6 +536,23 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+ }
+ EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
+
++/**
++ * spi_mem_adjust_op_freq() - Adjust the frequency of a SPI mem operation to
++ * match controller, PCB and chip limitations
++ * @mem: the SPI memory
++ * @op: the operation to adjust
++ *
++ * Some chips have per-op frequency limitations and must adapt the maximum
++ * speed. This function allows SPI mem drivers to set @op->max_freq to the
++ * maximum supported value.
++ */
++void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op)
++{
++ if (!op->max_freq || op->max_freq > mem->spi->max_speed_hz)
++ op->max_freq = mem->spi->max_speed_hz;
++}
++EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);
++
+ static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+ {
+diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
+index f866d5c8ed32a..44b7ecee0e74c 100644
+--- a/include/linux/spi/spi-mem.h
++++ b/include/linux/spi/spi-mem.h
+@@ -68,6 +68,9 @@ enum spi_mem_data_dir {
+ SPI_MEM_DATA_OUT,
+ };
+
++#define SPI_MEM_OP_MAX_FREQ(__freq) \
++ .max_freq = __freq
++
+ /**
+ * struct spi_mem_op - describes a SPI memory operation
+ * @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is
+@@ -95,6 +98,9 @@ enum spi_mem_data_dir {
+ * operation does not involve transferring data
+ * @data.buf.in: input buffer (must be DMA-able)
+ * @data.buf.out: output buffer (must be DMA-able)
++ * @max_freq: frequency limitation wrt this operation. 0 means there is no
++ * specific constraint and the highest achievable frequency can be
++ * attempted.
+ */
+ struct spi_mem_op {
+ struct {
+@@ -132,14 +138,17 @@ struct spi_mem_op {
+ const void *out;
+ } buf;
+ } data;
++
++ unsigned int max_freq;
+ };
+
+-#define SPI_MEM_OP(__cmd, __addr, __dummy, __data) \
++#define SPI_MEM_OP(__cmd, __addr, __dummy, __data, ...) \
+ { \
+ .cmd = __cmd, \
+ .addr = __addr, \
+ .dummy = __dummy, \
+ .data = __data, \
++ __VA_ARGS__ \
+ }
+
+ /**
+@@ -365,6 +374,7 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
+ #endif /* CONFIG_SPI_MEM */
+
+ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
++void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op);
+
+ bool spi_mem_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op);
+--
+2.39.5
+
diff --git a/queue-6.12/usb-typec-tcpm-pssourceofftimer-timeout-in-pr_swap-e.patch b/queue-6.12/usb-typec-tcpm-pssourceofftimer-timeout-in-pr_swap-e.patch
new file mode 100644
index 0000000000..98b05c94c5
--- /dev/null
+++ b/queue-6.12/usb-typec-tcpm-pssourceofftimer-timeout-in-pr_swap-e.patch
@@ -0,0 +1,54 @@
+From 2c935319f2f2929f170a9c965e04fb6e920aac87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Jul 2025 17:41:11 -0400
+Subject: usb: typec: tcpm: PSSourceOffTimer timeout in PR_Swap enters
+ ERROR_RECOVERY
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[ Upstream commit 659f5d55feb75782bd46cf130da3c1f240afe9ba ]
+
+As PD2.0 spec ("6.5.6.2 PSSourceOffTimer"),the PSSourceOffTimer is
+used by the Policy Engine in Dual-Role Power device that is currently
+acting as a Sink to timeout on a PS_RDY Message during a Power Role
+Swap sequence. This condition leads to a Hard Reset for USB Type-A and
+Type-B Plugs and Error Recovery for Type-C plugs and return to USB
+Default Operation.
+
+Therefore, after PSSourceOffTimer timeout, the tcpm state machine should
+switch from PR_SWAP_SNK_SRC_SINK_OFF to ERROR_RECOVERY. This can also
+solve the test items in the USB power delivery compliance test:
+TEST.PD.PROT.SNK.12 PR_Swap – PSSourceOffTimer Timeout
+
+[1] https://usb.org/document-library/usb-power-delivery-compliance-test-specification-0/USB_PD3_CTS_Q4_2025_OR.zip
+
+Fixes: f0690a25a140 ("staging: typec: USB Type-C Port Manager (tcpm)")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Jos Wang <joswang@lenovo.com>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Tested-by: Amit Sunil Dhamne <amitsd@google.com>
+Link: https://lore.kernel.org/r/20250213134921.3798-1-joswang1221@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/typec/tcpm/tcpm.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
+index 1d8e760df483c..9838a2c8c1b85 100644
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -5566,8 +5566,7 @@ static void run_state_machine(struct tcpm_port *port)
+ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB,
+ port->pps_data.active, 0);
+ tcpm_set_charge(port, false);
+- tcpm_set_state(port, hard_reset_state(port),
+- PD_T_PS_SOURCE_OFF);
++ tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_OFF);
+ break;
+ case PR_SWAP_SNK_SRC_SOURCE_ON:
+ tcpm_enable_auto_vbus_discharge(port, true);
+--
+2.39.5
+