--- /dev/null
+From 5ac28110ac4e6591b9a3ecbb3d2bdae6cff04bf1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 18:31:29 +0100
+Subject: ARM: dts: qcom: sdx55: fix pdc '#interrupt-cells'
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit cc25bd06c16aa582596a058d375b2e3133f79b93 ]
+
+The Qualcomm PDC interrupt controller binding expects two cells in
+interrupt specifiers.
+
+Fixes: 9d038b2e62de ("ARM: dts: qcom: Add SDX55 platform and MTP board support")
+Cc: stable@vger.kernel.org # 5.12
+Cc: Manivannan Sadhasivam <mani@kernel.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20231213173131.29436-2-johan+linaro@kernel.org
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/qcom-sdx55.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom-sdx55.dtsi
+index 4e7381d0e205..e8b4cbd39413 100644
+--- a/arch/arm/boot/dts/qcom-sdx55.dtsi
++++ b/arch/arm/boot/dts/qcom-sdx55.dtsi
+@@ -447,7 +447,7 @@ pdc: interrupt-controller@b210000 {
+ compatible = "qcom,sdx55-pdc", "qcom,pdc";
+ reg = <0x0b210000 0x30000>;
+ qcom,pdc-ranges = <0 179 52>;
+- #interrupt-cells = <3>;
++ #interrupt-cells = <2>;
+ interrupt-parent = <&intc>;
+ interrupt-controller;
+ };
+--
+2.43.0
+
--- /dev/null
+From 3a22928cb52748862acefd72fc12c1938ea91a7f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 18:31:30 +0100
+Subject: ARM: dts: qcom: sdx55: fix USB DP/DM HS PHY interrupts
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit de95f139394a5ed82270f005bc441d2e7c1e51b7 ]
+
+The USB DP/DM HS PHY interrupts need to be provided by the PDC interrupt
+controller in order to be able to wake the system up from low-power
+states and to be able to detect disconnect events, which requires
+triggering on falling edges.
+
+A recent commit updated the trigger type but failed to change the
+interrupt provider as required. This leads to the current Linux driver
+failing to probe instead of printing an error during suspend and USB
+wakeup not working as intended.
+
+Fixes: d0ec3c4c11c3 ("ARM: dts: qcom: sdx55: fix USB wakeup interrupt types")
+Fixes: fea4b41022f3 ("ARM: dts: qcom: sdx55: Add USB3 and PHY support")
+Cc: stable@vger.kernel.org # 5.12
+Cc: Manivannan Sadhasivam <mani@kernel.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20231213173131.29436-3-johan+linaro@kernel.org
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/qcom-sdx55.dtsi | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/boot/dts/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom-sdx55.dtsi
+index e8b4cbd39413..9c0d2432f105 100644
+--- a/arch/arm/boot/dts/qcom-sdx55.dtsi
++++ b/arch/arm/boot/dts/qcom-sdx55.dtsi
+@@ -420,10 +420,10 @@ usb: usb@a6f8800 {
+ <&gcc GCC_USB30_MASTER_CLK>;
+ assigned-clock-rates = <19200000>, <200000000>;
+
+- interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 158 IRQ_TYPE_EDGE_BOTH>,
+- <GIC_SPI 157 IRQ_TYPE_EDGE_BOTH>;
++ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
++ <&intc GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
++ <&pdc 11 IRQ_TYPE_EDGE_BOTH>,
++ <&pdc 10 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "hs_phy_irq", "ss_phy_irq",
+ "dm_hs_phy_irq", "dp_hs_phy_irq";
+
+--
+2.43.0
+
--- /dev/null
+From d1538f20b12a7550139abe78d64ab65a7624b39d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 18:31:31 +0100
+Subject: ARM: dts: qcom: sdx55: fix USB SS wakeup
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit 710dd03464e4ab5b3d329768388b165d61958577 ]
+
+The USB SS PHY interrupt needs to be provided by the PDC interrupt
+controller in order to be able to wake the system up from low-power
+states.
+
+Fixes: fea4b41022f3 ("ARM: dts: qcom: sdx55: Add USB3 and PHY support")
+Cc: stable@vger.kernel.org # 5.12
+Cc: Manivannan Sadhasivam <mani@kernel.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20231213173131.29436-4-johan+linaro@kernel.org
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/qcom-sdx55.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom-sdx55.dtsi
+index 9c0d2432f105..67159e8608ed 100644
+--- a/arch/arm/boot/dts/qcom-sdx55.dtsi
++++ b/arch/arm/boot/dts/qcom-sdx55.dtsi
+@@ -421,7 +421,7 @@ usb: usb@a6f8800 {
+ assigned-clock-rates = <19200000>, <200000000>;
+
+ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+- <&intc GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
++ <&pdc 51 IRQ_TYPE_LEVEL_HIGH>,
+ <&pdc 11 IRQ_TYPE_EDGE_BOTH>,
+ <&pdc 10 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "hs_phy_irq", "ss_phy_irq",
+--
+2.43.0
+
--- /dev/null
+From 81ab42f89ee8b35f438d2e21b318d12459f2b32e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Nov 2023 17:43:21 +0100
+Subject: ARM: dts: qcom: sdx55: fix USB wakeup interrupt types
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ Upstream commit d0ec3c4c11c3b30e1f2d344973b2a7bf0f986734 ]
+
+The DP/DM wakeup interrupts are edge triggered and which edge to trigger
+on depends on use-case and whether a Low speed or Full/High speed device
+is connected.
+
+Fixes: fea4b41022f3 ("ARM: dts: qcom: sdx55: Add USB3 and PHY support")
+Cc: stable@vger.kernel.org # 5.12
+Cc: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20231120164331.8116-2-johan+linaro@kernel.org
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/qcom-sdx55.dtsi | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/boot/dts/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom-sdx55.dtsi
+index 73fa0ef6b69e..4e7381d0e205 100644
+--- a/arch/arm/boot/dts/qcom-sdx55.dtsi
++++ b/arch/arm/boot/dts/qcom-sdx55.dtsi
+@@ -422,8 +422,8 @@ usb: usb@a6f8800 {
+
+ interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
+- <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
++ <GIC_SPI 158 IRQ_TYPE_EDGE_BOTH>,
++ <GIC_SPI 157 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "hs_phy_irq", "ss_phy_irq",
+ "dm_hs_phy_irq", "dp_hs_phy_irq";
+
+--
+2.43.0
+
--- /dev/null
+From d4e1dc126dce97720f2aed7d74115256f8db1475 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 6 Dec 2023 23:15:54 +0100
+Subject: ARM: dts: samsung: exynos4210-i9100: Unconditionally enable LDO12
+
+From: Paul Cercueil <paul@crapouillou.net>
+
+[ Upstream commit 84228d5e29dbc7a6be51e221000e1d122125826c ]
+
+The kernel hangs for a good 12 seconds without any info being printed to
+dmesg, very early in the boot process, if this regulator is not enabled.
+
+Force-enable it to work around this issue, until we know more about the
+underlying problem.
+
+Signed-off-by: Paul Cercueil <paul@crapouillou.net>
+Fixes: 8620cc2f99b7 ("ARM: dts: exynos: Add devicetree file for the Galaxy S2")
+Cc: stable@vger.kernel.org # v5.8+
+Link: https://lore.kernel.org/r/20231206221556.15348-2-paul@crapouillou.net
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/boot/dts/exynos4210-i9100.dts | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/boot/dts/exynos4210-i9100.dts b/arch/arm/boot/dts/exynos4210-i9100.dts
+index 93880bdbcad9..8232d843bfe0 100644
+--- a/arch/arm/boot/dts/exynos4210-i9100.dts
++++ b/arch/arm/boot/dts/exynos4210-i9100.dts
+@@ -520,6 +520,14 @@ vtcam_reg: LDO12 {
+ regulator-name = "VT_CAM_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
++
++ /*
++ * Force-enable this regulator; otherwise the
++ * kernel hangs very early in the boot process
++ * for about 12 seconds, without apparent
++ * reason.
++ */
++ regulator-always-on;
+ };
+
+ vcclcd_reg: LDO13 {
+--
+2.43.0
+
--- /dev/null
+From 2b5a8427f3f452bd6c02e781473eea4d4dd3f65d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Dec 2021 15:39:58 -0500
+Subject: btrfs: add definition for EXTENT_TREE_V2
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+[ Upstream commit 2c7d2a230237e7c43fa067d695937b7e484bb92a ]
+
+This adds the initial definition of the EXTENT_TREE_V2 incompat feature
+flag. This also hides the support behind CONFIG_BTRFS_DEBUG.
+
+THIS IS A IN DEVELOPMENT FORMAT CHANGE, DO NOT USE UNLESS YOU ARE A
+DEVELOPER OR A TESTER.
+
+The format is in flux and will be added in stages, any fs will need to
+be re-made between updates to the format.
+
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 7081929ab257 ("btrfs: don't abort filesystem when attempting to snapshot deleted subvolume")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ctree.h | 21 +++++++++++++++++++++
+ fs/btrfs/sysfs.c | 5 ++++-
+ include/uapi/linux/btrfs.h | 1 +
+ 3 files changed, 26 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
+index 7905f178efa3..17ebcf19b444 100644
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -282,6 +282,26 @@ struct btrfs_super_block {
+ #define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL
+ #define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL
+
++#ifdef CONFIG_BTRFS_DEBUG
++/*
++ * Extent tree v2 supported only with CONFIG_BTRFS_DEBUG
++ */
++#define BTRFS_FEATURE_INCOMPAT_SUPP \
++ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
++ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
++ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
++ BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \
++ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \
++ BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD | \
++ BTRFS_FEATURE_INCOMPAT_RAID56 | \
++ BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \
++ BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \
++ BTRFS_FEATURE_INCOMPAT_NO_HOLES | \
++ BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
++ BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
++ BTRFS_FEATURE_INCOMPAT_ZONED | \
++ BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2)
++#else
+ #define BTRFS_FEATURE_INCOMPAT_SUPP \
+ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
+ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
+@@ -296,6 +316,7 @@ struct btrfs_super_block {
+ BTRFS_FEATURE_INCOMPAT_METADATA_UUID | \
+ BTRFS_FEATURE_INCOMPAT_RAID1C34 | \
+ BTRFS_FEATURE_INCOMPAT_ZONED)
++#endif
+
+ #define BTRFS_FEATURE_INCOMPAT_SAFE_SET \
+ (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
+diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
+index 899dda6eb835..93a9dfbc8d13 100644
+--- a/fs/btrfs/sysfs.c
++++ b/fs/btrfs/sysfs.c
+@@ -283,9 +283,11 @@ BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES);
+ BTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID);
+ BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE);
+ BTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34);
+-/* Remove once support for zoned allocation is feature complete */
+ #ifdef CONFIG_BTRFS_DEBUG
++/* Remove once support for zoned allocation is feature complete */
+ BTRFS_FEAT_ATTR_INCOMPAT(zoned, ZONED);
++/* Remove once support for extent tree v2 is feature complete */
++BTRFS_FEAT_ATTR_INCOMPAT(extent_tree_v2, EXTENT_TREE_V2);
+ #endif
+ #ifdef CONFIG_FS_VERITY
+ BTRFS_FEAT_ATTR_COMPAT_RO(verity, VERITY);
+@@ -314,6 +316,7 @@ static struct attribute *btrfs_supported_feature_attrs[] = {
+ BTRFS_FEAT_ATTR_PTR(raid1c34),
+ #ifdef CONFIG_BTRFS_DEBUG
+ BTRFS_FEAT_ATTR_PTR(zoned),
++ BTRFS_FEAT_ATTR_PTR(extent_tree_v2),
+ #endif
+ #ifdef CONFIG_FS_VERITY
+ BTRFS_FEAT_ATTR_PTR(verity),
+diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
+index 4693b6ba30a1..493b10b9fedd 100644
+--- a/include/uapi/linux/btrfs.h
++++ b/include/uapi/linux/btrfs.h
+@@ -310,6 +310,7 @@ struct btrfs_ioctl_fs_info_args {
+ #define BTRFS_FEATURE_INCOMPAT_METADATA_UUID (1ULL << 10)
+ #define BTRFS_FEATURE_INCOMPAT_RAID1C34 (1ULL << 11)
+ #define BTRFS_FEATURE_INCOMPAT_ZONED (1ULL << 12)
++#define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 (1ULL << 13)
+
+ struct btrfs_ioctl_feature_flags {
+ __u64 compat_flags;
+--
+2.43.0
+
--- /dev/null
+From 89c9aa2ee17347ff34f87961e2c1287bd351d3cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Jan 2024 11:48:46 -0800
+Subject: btrfs: don't abort filesystem when attempting to snapshot deleted
+ subvolume
+
+From: Omar Sandoval <osandov@fb.com>
+
+[ Upstream commit 7081929ab2572920e94d70be3d332e5c9f97095a ]
+
+If the source file descriptor to the snapshot ioctl refers to a deleted
+subvolume, we get the following abort:
+
+ BTRFS: Transaction aborted (error -2)
+ WARNING: CPU: 0 PID: 833 at fs/btrfs/transaction.c:1875 create_pending_snapshot+0x1040/0x1190 [btrfs]
+ Modules linked in: pata_acpi btrfs ata_piix libata scsi_mod virtio_net blake2b_generic xor net_failover virtio_rng failover scsi_common rng_core raid6_pq libcrc32c
+ CPU: 0 PID: 833 Comm: t_snapshot_dele Not tainted 6.7.0-rc6 #2
+ Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-1.fc39 04/01/2014
+ RIP: 0010:create_pending_snapshot+0x1040/0x1190 [btrfs]
+ RSP: 0018:ffffa09c01337af8 EFLAGS: 00010282
+ RAX: 0000000000000000 RBX: ffff9982053e7c78 RCX: 0000000000000027
+ RDX: ffff99827dc20848 RSI: 0000000000000001 RDI: ffff99827dc20840
+ RBP: ffffa09c01337c00 R08: 0000000000000000 R09: ffffa09c01337998
+ R10: 0000000000000003 R11: ffffffffb96da248 R12: fffffffffffffffe
+ R13: ffff99820535bb28 R14: ffff99820b7bd000 R15: ffff99820381ea80
+ FS: 00007fe20aadabc0(0000) GS:ffff99827dc00000(0000) knlGS:0000000000000000
+ CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ CR2: 0000559a120b502f CR3: 00000000055b6000 CR4: 00000000000006f0
+ Call Trace:
+ <TASK>
+ ? create_pending_snapshot+0x1040/0x1190 [btrfs]
+ ? __warn+0x81/0x130
+ ? create_pending_snapshot+0x1040/0x1190 [btrfs]
+ ? report_bug+0x171/0x1a0
+ ? handle_bug+0x3a/0x70
+ ? exc_invalid_op+0x17/0x70
+ ? asm_exc_invalid_op+0x1a/0x20
+ ? create_pending_snapshot+0x1040/0x1190 [btrfs]
+ ? create_pending_snapshot+0x1040/0x1190 [btrfs]
+ create_pending_snapshots+0x92/0xc0 [btrfs]
+ btrfs_commit_transaction+0x66b/0xf40 [btrfs]
+ btrfs_mksubvol+0x301/0x4d0 [btrfs]
+ btrfs_mksnapshot+0x80/0xb0 [btrfs]
+ __btrfs_ioctl_snap_create+0x1c2/0x1d0 [btrfs]
+ btrfs_ioctl_snap_create_v2+0xc4/0x150 [btrfs]
+ btrfs_ioctl+0x8a6/0x2650 [btrfs]
+ ? kmem_cache_free+0x22/0x340
+ ? do_sys_openat2+0x97/0xe0
+ __x64_sys_ioctl+0x97/0xd0
+ do_syscall_64+0x46/0xf0
+ entry_SYSCALL_64_after_hwframe+0x6e/0x76
+ RIP: 0033:0x7fe20abe83af
+ RSP: 002b:00007ffe6eff1360 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
+ RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007fe20abe83af
+ RDX: 00007ffe6eff23c0 RSI: 0000000050009417 RDI: 0000000000000003
+ RBP: 0000000000000003 R08: 0000000000000000 R09: 00007fe20ad16cd0
+ R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+ R13: 00007ffe6eff13c0 R14: 00007fe20ad45000 R15: 0000559a120b6d58
+ </TASK>
+ ---[ end trace 0000000000000000 ]---
+ BTRFS: error (device vdc: state A) in create_pending_snapshot:1875: errno=-2 No such entry
+ BTRFS info (device vdc: state EA): forced readonly
+ BTRFS warning (device vdc: state EA): Skipping commit of aborted transaction.
+ BTRFS: error (device vdc: state EA) in cleanup_transaction:2055: errno=-2 No such entry
+
+This happens because create_pending_snapshot() initializes the new root
+item as a copy of the source root item. This includes the refs field,
+which is 0 for a deleted subvolume. The call to btrfs_insert_root()
+therefore inserts a root with refs == 0. btrfs_get_new_fs_root() then
+finds the root and returns -ENOENT if refs == 0, which causes
+create_pending_snapshot() to abort.
+
+Fix it by checking the source root's refs before attempting the
+snapshot, but after locking subvol_sem to avoid racing with deletion.
+
+CC: stable@vger.kernel.org # 4.14+
+Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
+Reviewed-by: Anand Jain <anand.jain@oracle.com>
+Signed-off-by: Omar Sandoval <osandov@fb.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/ioctl.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
+index 37f4370a779d..768f58a53a94 100644
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -725,6 +725,9 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
+ struct btrfs_trans_handle *trans;
+ int ret;
+
++ if (btrfs_root_refs(&root->root_item) == 0)
++ return -ENOENT;
++
+ if (btrfs_root_refs(&root->root_item) == 0)
+ return -ENOENT;
+
+--
+2.43.0
+
--- /dev/null
+From 1dd0380d4d6f0ebd7690cfcda6bc9fe0ce3f179a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 31 Oct 2023 15:21:05 +0530
+Subject: bus: mhi: host: Add alignment check for event ring read pointer
+
+From: Krishna chaitanya chundru <quic_krichai@quicinc.com>
+
+[ Upstream commit eff9704f5332a13b08fbdbe0f84059c9e7051d5f ]
+
+Though we do check the event ring read pointer by "is_valid_ring_ptr"
+to make sure it is in the buffer range, but there is another risk the
+pointer may be not aligned. Since we are expecting event ring elements
+are 128 bits(struct mhi_ring_element) aligned, an unaligned read pointer
+could lead to multiple issues like DoS or ring buffer memory corruption.
+
+So add a alignment check for event ring read pointer.
+
+Fixes: ec32332df764 ("bus: mhi: core: Sanity check values from remote device before use")
+cc: stable@vger.kernel.org
+Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
+Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20231031-alignment_check-v2-1-1441db7c5efd@quicinc.com
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bus/mhi/host/main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
+index 23bd1db94558..1cb7c60594f1 100644
+--- a/drivers/bus/mhi/host/main.c
++++ b/drivers/bus/mhi/host/main.c
+@@ -267,7 +267,8 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl,
+
+ static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr)
+ {
+- return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len;
++ return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len &&
++ !(addr & (sizeof(struct mhi_ring_element) - 1));
+ }
+
+ int mhi_destroy_device(struct device *dev, void *data)
+--
+2.43.0
+
--- /dev/null
+From 09068651c6304d67704c3e713d38c722e2c0f1e4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Mar 2022 21:33:06 +0530
+Subject: bus: mhi: host: Rename "struct mhi_tre" to "struct mhi_ring_element"
+
+From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+[ Upstream commit 84f5f31f110e5e8cd5581e8efdbf8c369e962eb9 ]
+
+Structure "struct mhi_tre" is representing a generic MHI ring element and
+not specifically a Transfer Ring Element (TRE). Fix the naming.
+
+Reviewed-by: Alex Elder <elder@linaro.org>
+Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Link: https://lore.kernel.org/r/20220301160308.107452-9-manivannan.sadhasivam@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: eff9704f5332 ("bus: mhi: host: Add alignment check for event ring read pointer")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bus/mhi/host/init.c | 6 +++---
+ drivers/bus/mhi/host/internal.h | 2 +-
+ drivers/bus/mhi/host/main.c | 20 ++++++++++----------
+ 3 files changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
+index 829d4fca7ddc..7ccc5cd27fd0 100644
+--- a/drivers/bus/mhi/host/init.c
++++ b/drivers/bus/mhi/host/init.c
+@@ -338,7 +338,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
+ er_ctxt->msivec = cpu_to_le32(mhi_event->irq);
+ mhi_event->db_cfg.db_mode = true;
+
+- ring->el_size = sizeof(struct mhi_tre);
++ ring->el_size = sizeof(struct mhi_ring_element);
+ ring->len = ring->el_size * ring->elements;
+ ret = mhi_alloc_aligned_ring(mhi_cntrl, ring, ring->len);
+ if (ret)
+@@ -370,7 +370,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
+ for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++, cmd_ctxt++) {
+ struct mhi_ring *ring = &mhi_cmd->ring;
+
+- ring->el_size = sizeof(struct mhi_tre);
++ ring->el_size = sizeof(struct mhi_ring_element);
+ ring->elements = CMD_EL_PER_RING;
+ ring->len = ring->el_size * ring->elements;
+ ret = mhi_alloc_aligned_ring(mhi_cntrl, ring, ring->len);
+@@ -613,7 +613,7 @@ int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
+
+ buf_ring = &mhi_chan->buf_ring;
+ tre_ring = &mhi_chan->tre_ring;
+- tre_ring->el_size = sizeof(struct mhi_tre);
++ tre_ring->el_size = sizeof(struct mhi_ring_element);
+ tre_ring->len = tre_ring->el_size * tre_ring->elements;
+ chan_ctxt = &mhi_cntrl->mhi_ctxt->chan_ctxt[mhi_chan->chan];
+ ret = mhi_alloc_aligned_ring(mhi_cntrl, tre_ring, tre_ring->len);
+diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
+index 71f181402be9..df65bb17fdba 100644
+--- a/drivers/bus/mhi/host/internal.h
++++ b/drivers/bus/mhi/host/internal.h
+@@ -257,7 +257,7 @@ struct mhi_ctxt {
+ dma_addr_t cmd_ctxt_addr;
+ };
+
+-struct mhi_tre {
++struct mhi_ring_element {
+ __le64 ptr;
+ __le32 dword[2];
+ };
+diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
+index 0d35acb2f7c0..23bd1db94558 100644
+--- a/drivers/bus/mhi/host/main.c
++++ b/drivers/bus/mhi/host/main.c
+@@ -556,7 +556,7 @@ static void mhi_recycle_ev_ring_element(struct mhi_controller *mhi_cntrl,
+ }
+
+ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
+- struct mhi_tre *event,
++ struct mhi_ring_element *event,
+ struct mhi_chan *mhi_chan)
+ {
+ struct mhi_ring *buf_ring, *tre_ring;
+@@ -592,7 +592,7 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
+ case MHI_EV_CC_EOT:
+ {
+ dma_addr_t ptr = MHI_TRE_GET_EV_PTR(event);
+- struct mhi_tre *local_rp, *ev_tre;
++ struct mhi_ring_element *local_rp, *ev_tre;
+ void *dev_rp;
+ struct mhi_buf_info *buf_info;
+ u16 xfer_len;
+@@ -695,7 +695,7 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
+ }
+
+ static int parse_rsc_event(struct mhi_controller *mhi_cntrl,
+- struct mhi_tre *event,
++ struct mhi_ring_element *event,
+ struct mhi_chan *mhi_chan)
+ {
+ struct mhi_ring *buf_ring, *tre_ring;
+@@ -759,12 +759,12 @@ static int parse_rsc_event(struct mhi_controller *mhi_cntrl,
+ }
+
+ static void mhi_process_cmd_completion(struct mhi_controller *mhi_cntrl,
+- struct mhi_tre *tre)
++ struct mhi_ring_element *tre)
+ {
+ dma_addr_t ptr = MHI_TRE_GET_EV_PTR(tre);
+ struct mhi_cmd *cmd_ring = &mhi_cntrl->mhi_cmd[PRIMARY_CMD_RING];
+ struct mhi_ring *mhi_ring = &cmd_ring->ring;
+- struct mhi_tre *cmd_pkt;
++ struct mhi_ring_element *cmd_pkt;
+ struct mhi_chan *mhi_chan;
+ u32 chan;
+
+@@ -797,7 +797,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
+ struct mhi_event *mhi_event,
+ u32 event_quota)
+ {
+- struct mhi_tre *dev_rp, *local_rp;
++ struct mhi_ring_element *dev_rp, *local_rp;
+ struct mhi_ring *ev_ring = &mhi_event->ring;
+ struct mhi_event_ctxt *er_ctxt =
+ &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
+@@ -967,7 +967,7 @@ int mhi_process_data_event_ring(struct mhi_controller *mhi_cntrl,
+ struct mhi_event *mhi_event,
+ u32 event_quota)
+ {
+- struct mhi_tre *dev_rp, *local_rp;
++ struct mhi_ring_element *dev_rp, *local_rp;
+ struct mhi_ring *ev_ring = &mhi_event->ring;
+ struct mhi_event_ctxt *er_ctxt =
+ &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
+@@ -1188,7 +1188,7 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
+ struct mhi_buf_info *info, enum mhi_flags flags)
+ {
+ struct mhi_ring *buf_ring, *tre_ring;
+- struct mhi_tre *mhi_tre;
++ struct mhi_ring_element *mhi_tre;
+ struct mhi_buf_info *buf_info;
+ int eot, eob, chain, bei;
+ int ret;
+@@ -1266,7 +1266,7 @@ int mhi_send_cmd(struct mhi_controller *mhi_cntrl,
+ struct mhi_chan *mhi_chan,
+ enum mhi_cmd_type cmd)
+ {
+- struct mhi_tre *cmd_tre = NULL;
++ struct mhi_ring_element *cmd_tre = NULL;
+ struct mhi_cmd *mhi_cmd = &mhi_cntrl->mhi_cmd[PRIMARY_CMD_RING];
+ struct mhi_ring *ring = &mhi_cmd->ring;
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+@@ -1524,7 +1524,7 @@ static void mhi_mark_stale_events(struct mhi_controller *mhi_cntrl,
+ int chan)
+
+ {
+- struct mhi_tre *dev_rp, *local_rp;
++ struct mhi_ring_element *dev_rp, *local_rp;
+ struct mhi_ring *ev_ring;
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ unsigned long flags;
+--
+2.43.0
+
--- /dev/null
+From 2af81d33442247fee488492a78d15042d9e78bb1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Dec 2021 17:12:18 +0100
+Subject: cpufreq: intel_pstate: Drop redundant intel_pstate_get_hwp_cap() call
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 458b03f81afbb27143c45d47c2d8f418b2ba2407 ]
+
+It is not necessary to call intel_pstate_get_hwp_cap() from
+intel_pstate_update_perf_limits(), because it gets called from
+intel_pstate_verify_cpu_policy() which is either invoked directly
+right before intel_pstate_update_perf_limits(), in
+intel_cpufreq_verify_policy() in the passive mode, or called
+from driver callbacks in a sequence that causes it to be followed
+by an immediate intel_pstate_update_perf_limits().
+
+Namely, in the active mode intel_cpufreq_verify_policy() is called
+by intel_pstate_verify_policy() which is the ->verify() callback
+routine of intel_pstate and gets called by the cpufreq core right
+before intel_pstate_set_policy(), which is the driver's ->setoplicy()
+callback routine, where intel_pstate_update_perf_limits() is called.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Stable-dep-of: 192cdb1c907f ("cpufreq: intel_pstate: Refine computation of P-state for given frequency")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/intel_pstate.c | 20 ++++++++------------
+ 1 file changed, 8 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index 736cb2cfcbb0..f2a94afb6eec 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -2332,18 +2332,14 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
+ * HWP needs some special consideration, because HWP_REQUEST uses
+ * abstract values to represent performance rather than pure ratios.
+ */
+- if (hwp_active) {
+- intel_pstate_get_hwp_cap(cpu);
+-
+- if (cpu->pstate.scaling != perf_ctl_scaling) {
+- int scaling = cpu->pstate.scaling;
+- int freq;
+-
+- freq = max_policy_perf * perf_ctl_scaling;
+- max_policy_perf = DIV_ROUND_UP(freq, scaling);
+- freq = min_policy_perf * perf_ctl_scaling;
+- min_policy_perf = DIV_ROUND_UP(freq, scaling);
+- }
++ if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) {
++ int scaling = cpu->pstate.scaling;
++ int freq;
++
++ freq = max_policy_perf * perf_ctl_scaling;
++ max_policy_perf = DIV_ROUND_UP(freq, scaling);
++ freq = min_policy_perf * perf_ctl_scaling;
++ min_policy_perf = DIV_ROUND_UP(freq, scaling);
+ }
+
+ pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n",
+--
+2.43.0
+
--- /dev/null
+From 1eeaa96a9ad602510eb2271ad6cb7f9255c8ab7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jan 2024 15:18:11 +0100
+Subject: cpufreq: intel_pstate: Refine computation of P-state for given
+ frequency
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 192cdb1c907fd8df2d764c5bb17496e415e59391 ]
+
+On systems using HWP, if a given frequency is equal to the maximum turbo
+frequency or the maximum non-turbo frequency, the HWP performance level
+corresponding to it is already known and can be used directly without
+any computation.
+
+Accordingly, adjust the code to use the known HWP performance levels in
+the cases mentioned above.
+
+This also helps to avoid limiting CPU capacity artificially in some
+cases when the BIOS produces the HWP_CAP numbers using a different
+E-core-to-P-core performance scaling factor than expected by the kernel.
+
+Fixes: f5c8cf2a4992 ("cpufreq: intel_pstate: hybrid: Use known scaling factor for P-cores")
+Cc: 6.1+ <stable@vger.kernel.org> # 6.1+
+Tested-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/intel_pstate.c | 55 +++++++++++++++++++++-------------
+ 1 file changed, 34 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
+index f2a94afb6eec..dd5f4eee9ffb 100644
+--- a/drivers/cpufreq/intel_pstate.c
++++ b/drivers/cpufreq/intel_pstate.c
+@@ -490,6 +490,30 @@ static inline int intel_pstate_get_cppc_guaranteed(int cpu)
+ }
+ #endif /* CONFIG_ACPI_CPPC_LIB */
+
++static int intel_pstate_freq_to_hwp_rel(struct cpudata *cpu, int freq,
++ unsigned int relation)
++{
++ if (freq == cpu->pstate.turbo_freq)
++ return cpu->pstate.turbo_pstate;
++
++ if (freq == cpu->pstate.max_freq)
++ return cpu->pstate.max_pstate;
++
++ switch (relation) {
++ case CPUFREQ_RELATION_H:
++ return freq / cpu->pstate.scaling;
++ case CPUFREQ_RELATION_C:
++ return DIV_ROUND_CLOSEST(freq, cpu->pstate.scaling);
++ }
++
++ return DIV_ROUND_UP(freq, cpu->pstate.scaling);
++}
++
++static int intel_pstate_freq_to_hwp(struct cpudata *cpu, int freq)
++{
++ return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L);
++}
++
+ /**
+ * intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels.
+ * @cpu: Target CPU.
+@@ -507,6 +531,7 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+ int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu);
+ int scaling = cpu->pstate.scaling;
++ int freq;
+
+ pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys);
+ pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo);
+@@ -520,16 +545,16 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
+ cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
+ perf_ctl_scaling);
+
+- cpu->pstate.max_pstate_physical =
+- DIV_ROUND_UP(perf_ctl_max_phys * perf_ctl_scaling,
+- scaling);
++ freq = perf_ctl_max_phys * perf_ctl_scaling;
++ cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
+
+- cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
++ freq = cpu->pstate.min_pstate * perf_ctl_scaling;
++ cpu->pstate.min_freq = freq;
+ /*
+ * Cast the min P-state value retrieved via pstate_funcs.get_min() to
+ * the effective range of HWP performance levels.
+ */
+- cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling);
++ cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq);
+ }
+
+ static inline void update_turbo_state(void)
+@@ -2333,13 +2358,12 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
+ * abstract values to represent performance rather than pure ratios.
+ */
+ if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) {
+- int scaling = cpu->pstate.scaling;
+ int freq;
+
+ freq = max_policy_perf * perf_ctl_scaling;
+- max_policy_perf = DIV_ROUND_UP(freq, scaling);
++ max_policy_perf = intel_pstate_freq_to_hwp(cpu, freq);
+ freq = min_policy_perf * perf_ctl_scaling;
+- min_policy_perf = DIV_ROUND_UP(freq, scaling);
++ min_policy_perf = intel_pstate_freq_to_hwp(cpu, freq);
+ }
+
+ pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n",
+@@ -2708,18 +2732,7 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy,
+
+ cpufreq_freq_transition_begin(policy, &freqs);
+
+- switch (relation) {
+- case CPUFREQ_RELATION_L:
+- target_pstate = DIV_ROUND_UP(freqs.new, cpu->pstate.scaling);
+- break;
+- case CPUFREQ_RELATION_H:
+- target_pstate = freqs.new / cpu->pstate.scaling;
+- break;
+- default:
+- target_pstate = DIV_ROUND_CLOSEST(freqs.new, cpu->pstate.scaling);
+- break;
+- }
+-
++ target_pstate = intel_pstate_freq_to_hwp_rel(cpu, freqs.new, relation);
+ target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, false);
+
+ freqs.new = target_pstate * cpu->pstate.scaling;
+@@ -2737,7 +2750,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
+
+ update_turbo_state();
+
+- target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling);
++ target_pstate = intel_pstate_freq_to_hwp(cpu, target_freq);
+
+ target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true);
+
+--
+2.43.0
+
--- /dev/null
+From f96406b56380e050b931160af004c27c740bcaa9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 21 Sep 2023 09:57:53 +0200
+Subject: fs/pipe: move check to pipe_has_watch_queue()
+
+From: Max Kellermann <max.kellermann@ionos.com>
+
+[ Upstream commit b4bd6b4bac8edd61eb8f7b836969d12c0c6af165 ]
+
+This declutters the code by reducing the number of #ifdefs and makes
+the watch_queue checks simpler. This has no runtime effect; the
+machine code is identical.
+
+Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
+Message-Id: <20230921075755.1378787-2-max.kellermann@ionos.com>
+Reviewed-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Stable-dep-of: e95aada4cb93 ("pipe: wakeup wr_wait after setting max_usage")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/pipe.c | 12 +++---------
+ include/linux/pipe_fs_i.h | 16 ++++++++++++++++
+ 2 files changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/fs/pipe.c b/fs/pipe.c
+index e08f0fe55584..1a43948c0c36 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -435,12 +435,10 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
+ goto out;
+ }
+
+-#ifdef CONFIG_WATCH_QUEUE
+- if (pipe->watch_queue) {
++ if (pipe_has_watch_queue(pipe)) {
+ ret = -EXDEV;
+ goto out;
+ }
+-#endif
+
+ /*
+ * If it wasn't empty we try to merge new data into
+@@ -1319,10 +1317,8 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
+ unsigned int nr_slots, size;
+ long ret = 0;
+
+-#ifdef CONFIG_WATCH_QUEUE
+- if (pipe->watch_queue)
++ if (pipe_has_watch_queue(pipe))
+ return -EBUSY;
+-#endif
+
+ size = round_pipe_size(arg);
+ nr_slots = size >> PAGE_SHIFT;
+@@ -1374,10 +1370,8 @@ struct pipe_inode_info *get_pipe_info(struct file *file, bool for_splice)
+
+ if (file->f_op != &pipefifo_fops || !pipe)
+ return NULL;
+-#ifdef CONFIG_WATCH_QUEUE
+- if (for_splice && pipe->watch_queue)
++ if (for_splice && pipe_has_watch_queue(pipe))
+ return NULL;
+-#endif
+ return pipe;
+ }
+
+diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
+index d15190b3e032..0613daf8997a 100644
+--- a/include/linux/pipe_fs_i.h
++++ b/include/linux/pipe_fs_i.h
+@@ -124,6 +124,22 @@ struct pipe_buf_operations {
+ bool (*get)(struct pipe_inode_info *, struct pipe_buffer *);
+ };
+
++/**
++ * pipe_has_watch_queue - Check whether the pipe is a watch_queue,
++ * i.e. it was created with O_NOTIFICATION_PIPE
++ * @pipe: The pipe to check
++ *
++ * Return: true if pipe is a watch queue, false otherwise.
++ */
++static inline bool pipe_has_watch_queue(const struct pipe_inode_info *pipe)
++{
++#ifdef CONFIG_WATCH_QUEUE
++ return pipe->watch_queue != NULL;
++#else
++ return false;
++#endif
++}
++
+ /**
+ * pipe_empty - Return true if the pipe is empty
+ * @head: The pipe ring head pointer
+--
+2.43.0
+
--- /dev/null
+From 4e84346099553d37dc99bd557b1d26292cd0e0d3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 21 Jan 2024 15:35:06 +0800
+Subject: ksmbd: fix global oob in ksmbd_nl_policy
+
+From: Lin Ma <linma@zju.edu.cn>
+
+[ Upstream commit ebeae8adf89d9a82359f6659b1663d09beec2faa ]
+
+Similar to a reported issue (check the commit b33fb5b801c6 ("net:
+qualcomm: rmnet: fix global oob in rmnet_policy"), my local fuzzer finds
+another global out-of-bounds read for policy ksmbd_nl_policy. See bug
+trace below:
+
+==================================================================
+BUG: KASAN: global-out-of-bounds in validate_nla lib/nlattr.c:386 [inline]
+BUG: KASAN: global-out-of-bounds in __nla_validate_parse+0x24af/0x2750 lib/nlattr.c:600
+Read of size 1 at addr ffffffff8f24b100 by task syz-executor.1/62810
+
+CPU: 0 PID: 62810 Comm: syz-executor.1 Tainted: G N 6.1.0 #3
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:88 [inline]
+ dump_stack_lvl+0x8b/0xb3 lib/dump_stack.c:106
+ print_address_description mm/kasan/report.c:284 [inline]
+ print_report+0x172/0x475 mm/kasan/report.c:395
+ kasan_report+0xbb/0x1c0 mm/kasan/report.c:495
+ validate_nla lib/nlattr.c:386 [inline]
+ __nla_validate_parse+0x24af/0x2750 lib/nlattr.c:600
+ __nla_parse+0x3e/0x50 lib/nlattr.c:697
+ __nlmsg_parse include/net/netlink.h:748 [inline]
+ genl_family_rcv_msg_attrs_parse.constprop.0+0x1b0/0x290 net/netlink/genetlink.c:565
+ genl_family_rcv_msg_doit+0xda/0x330 net/netlink/genetlink.c:734
+ genl_family_rcv_msg net/netlink/genetlink.c:833 [inline]
+ genl_rcv_msg+0x441/0x780 net/netlink/genetlink.c:850
+ netlink_rcv_skb+0x14f/0x410 net/netlink/af_netlink.c:2540
+ genl_rcv+0x24/0x40 net/netlink/genetlink.c:861
+ netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
+ netlink_unicast+0x54e/0x800 net/netlink/af_netlink.c:1345
+ netlink_sendmsg+0x930/0xe50 net/netlink/af_netlink.c:1921
+ sock_sendmsg_nosec net/socket.c:714 [inline]
+ sock_sendmsg+0x154/0x190 net/socket.c:734
+ ____sys_sendmsg+0x6df/0x840 net/socket.c:2482
+ ___sys_sendmsg+0x110/0x1b0 net/socket.c:2536
+ __sys_sendmsg+0xf3/0x1c0 net/socket.c:2565
+ do_syscall_x64 arch/x86/entry/common.c:50 [inline]
+ do_syscall_64+0x3b/0x90 arch/x86/entry/common.c:80
+ entry_SYSCALL_64_after_hwframe+0x63/0xcd
+RIP: 0033:0x7fdd66a8f359
+Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 f1 19 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007fdd65e00168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+RAX: ffffffffffffffda RBX: 00007fdd66bbcf80 RCX: 00007fdd66a8f359
+RDX: 0000000000000000 RSI: 0000000020000500 RDI: 0000000000000003
+RBP: 00007fdd66ada493 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+R13: 00007ffc84b81aff R14: 00007fdd65e00300 R15: 0000000000022000
+ </TASK>
+
+The buggy address belongs to the variable:
+ ksmbd_nl_policy+0x100/0xa80
+
+The buggy address belongs to the physical page:
+page:0000000034f47940 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1ccc4b
+flags: 0x200000000001000(reserved|node=0|zone=2)
+raw: 0200000000001000 ffffea00073312c8 ffffea00073312c8 0000000000000000
+raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000
+page dumped because: kasan: bad access detected
+
+Memory state around the buggy address:
+ ffffffff8f24b000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ ffffffff8f24b080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+>ffffffff8f24b100: f9 f9 f9 f9 00 00 f9 f9 f9 f9 f9 f9 00 00 07 f9
+ ^
+ ffffffff8f24b180: f9 f9 f9 f9 00 05 f9 f9 f9 f9 f9 f9 00 00 00 05
+ ffffffff8f24b200: f9 f9 f9 f9 00 00 03 f9 f9 f9 f9 f9 00 00 04 f9
+==================================================================
+
+To fix it, add a placeholder named __KSMBD_EVENT_MAX and let
+KSMBD_EVENT_MAX to be its original value - 1 according to what other
+netlink families do. Also change two sites that refer the
+KSMBD_EVENT_MAX to correct value.
+
+Cc: stable@vger.kernel.org
+Fixes: 0626e6641f6b ("cifsd: add server handler for central processing and tranport layers")
+Signed-off-by: Lin Ma <linma@zju.edu.cn>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ksmbd/ksmbd_netlink.h | 3 ++-
+ fs/ksmbd/transport_ipc.c | 4 ++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/fs/ksmbd/ksmbd_netlink.h b/fs/ksmbd/ksmbd_netlink.h
+index 821ed8e3cbee..ecffcb8a1557 100644
+--- a/fs/ksmbd/ksmbd_netlink.h
++++ b/fs/ksmbd/ksmbd_netlink.h
+@@ -304,7 +304,8 @@ enum ksmbd_event {
+ KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
+ KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE = 15,
+
+- KSMBD_EVENT_MAX
++ __KSMBD_EVENT_MAX,
++ KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1
+ };
+
+ /*
+diff --git a/fs/ksmbd/transport_ipc.c b/fs/ksmbd/transport_ipc.c
+index 9560c704033e..2c9662e32799 100644
+--- a/fs/ksmbd/transport_ipc.c
++++ b/fs/ksmbd/transport_ipc.c
+@@ -74,7 +74,7 @@ static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info)
+ static int handle_generic_event(struct sk_buff *skb, struct genl_info *info);
+ static int ksmbd_ipc_heartbeat_request(void);
+
+-static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX] = {
++static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = {
+ [KSMBD_EVENT_UNSPEC] = {
+ .len = 0,
+ },
+@@ -402,7 +402,7 @@ static int handle_generic_event(struct sk_buff *skb, struct genl_info *info)
+ return -EPERM;
+ #endif
+
+- if (type >= KSMBD_EVENT_MAX) {
++ if (type > KSMBD_EVENT_MAX) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+--
+2.43.0
+
--- /dev/null
+From 67cfccae23323c9254f098a15decfd5c9012e929 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Nov 2023 15:48:10 +0100
+Subject: media: mtk-jpeg: Fix use after free bug due to error path handling in
+ mtk_jpeg_dec_device_run
+
+From: Zheng Wang <zyytlz.wz@163.com>
+
+[ Upstream commit 206c857dd17d4d026de85866f1b5f0969f2a109e ]
+
+In mtk_jpeg_probe, &jpeg->job_timeout_work is bound with
+mtk_jpeg_job_timeout_work.
+
+In mtk_jpeg_dec_device_run, if error happens in
+mtk_jpeg_set_dec_dst, it will finally start the worker while
+mark the job as finished by invoking v4l2_m2m_job_finish.
+
+There are two methods to trigger the bug. If we remove the
+module, it which will call mtk_jpeg_remove to make cleanup.
+The possible sequence is as follows, which will cause a
+use-after-free bug.
+
+CPU0 CPU1
+mtk_jpeg_dec_... |
+ start worker |
+ |mtk_jpeg_job_timeout_work
+mtk_jpeg_remove |
+ v4l2_m2m_release |
+ kfree(m2m_dev); |
+ |
+ | v4l2_m2m_get_curr_priv
+ | m2m_dev->curr_ctx //use
+
+If we close the file descriptor, which will call mtk_jpeg_release,
+it will have a similar sequence.
+
+Fix this bug by starting timeout worker only if started jpegdec worker
+successfully. Then v4l2_m2m_job_finish will only be called in
+either mtk_jpeg_job_timeout_work or mtk_jpeg_dec_device_run.
+
+Fixes: b2f0d2724ba4 ("[media] vcodec: mediatek: Add Mediatek JPEG Decoder Driver")
+Signed-off-by: Zheng Wang <zyytlz.wz@163.com>
+Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+index bc84274ba87a..ba490b06ff70 100644
+--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
++++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+@@ -977,13 +977,13 @@ static void mtk_jpeg_dec_device_run(void *priv)
+ if (ret < 0)
+ goto dec_end;
+
+- schedule_delayed_work(&jpeg->job_timeout_work,
+- msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+-
+ mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
+ if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb))
+ goto dec_end;
+
++ schedule_delayed_work(&jpeg->job_timeout_work,
++ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
++
+ spin_lock_irqsave(&jpeg->hw_lock, flags);
+ mtk_jpeg_dec_reset(jpeg->reg_base);
+ mtk_jpeg_dec_set_config(jpeg->reg_base,
+--
+2.43.0
+
--- /dev/null
+From 251410828c1f87e2c887ef1a1337183170a2b484 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Oct 2023 18:34:27 +0530
+Subject: mm/sparsemem: fix race in accessing memory_section->usage
+
+From: Charan Teja Kalla <quic_charante@quicinc.com>
+
+[ Upstream commit 5ec8e8ea8b7783fab150cf86404fc38cb4db8800 ]
+
+The below race is observed on a PFN which falls into the device memory
+region with the system memory configuration where PFN's are such that
+[ZONE_NORMAL ZONE_DEVICE ZONE_NORMAL]. Since normal zone start and end
+pfn contains the device memory PFN's as well, the compaction triggered
+will try on the device memory PFN's too though they end up in NOP(because
+pfn_to_online_page() returns NULL for ZONE_DEVICE memory sections). When
+from other core, the section mappings are being removed for the
+ZONE_DEVICE region, that the PFN in question belongs to, on which
+compaction is currently being operated is resulting into the kernel crash
+with CONFIG_SPASEMEM_VMEMAP enabled. The crash logs can be seen at [1].
+
+compact_zone() memunmap_pages
+------------- ---------------
+__pageblock_pfn_to_page
+ ......
+ (a)pfn_valid():
+ valid_section()//return true
+ (b)__remove_pages()->
+ sparse_remove_section()->
+ section_deactivate():
+ [Free the array ms->usage and set
+ ms->usage = NULL]
+ pfn_section_valid()
+ [Access ms->usage which
+ is NULL]
+
+NOTE: From the above it can be said that the race is reduced to between
+the pfn_valid()/pfn_section_valid() and the section deactivate with
+SPASEMEM_VMEMAP enabled.
+
+The commit b943f045a9af("mm/sparse: fix kernel crash with
+pfn_section_valid check") tried to address the same problem by clearing
+the SECTION_HAS_MEM_MAP with the expectation of valid_section() returns
+false thus ms->usage is not accessed.
+
+Fix this issue by the below steps:
+
+a) Clear SECTION_HAS_MEM_MAP before freeing the ->usage.
+
+b) RCU protected read side critical section will either return NULL
+ when SECTION_HAS_MEM_MAP is cleared or can successfully access ->usage.
+
+c) Free the ->usage with kfree_rcu() and set ms->usage = NULL. No
+ attempt will be made to access ->usage after this as the
+ SECTION_HAS_MEM_MAP is cleared thus valid_section() return false.
+
+Thanks to David/Pavan for their inputs on this patch.
+
+[1] https://lore.kernel.org/linux-mm/994410bb-89aa-d987-1f50-f514903c55aa@quicinc.com/
+
+On Snapdragon SoC, with the mentioned memory configuration of PFN's as
+[ZONE_NORMAL ZONE_DEVICE ZONE_NORMAL], we are able to see bunch of
+issues daily while testing on a device farm.
+
+For this particular issue below is the log. Though the below log is
+not directly pointing to the pfn_section_valid(){ ms->usage;}, when we
+loaded this dump on T32 lauterbach tool, it is pointing.
+
+[ 540.578056] Unable to handle kernel NULL pointer dereference at
+virtual address 0000000000000000
+[ 540.578068] Mem abort info:
+[ 540.578070] ESR = 0x0000000096000005
+[ 540.578073] EC = 0x25: DABT (current EL), IL = 32 bits
+[ 540.578077] SET = 0, FnV = 0
+[ 540.578080] EA = 0, S1PTW = 0
+[ 540.578082] FSC = 0x05: level 1 translation fault
+[ 540.578085] Data abort info:
+[ 540.578086] ISV = 0, ISS = 0x00000005
+[ 540.578088] CM = 0, WnR = 0
+[ 540.579431] pstate: 82400005 (Nzcv daif +PAN -UAO +TCO -DIT -SSBSBTYPE=--)
+[ 540.579436] pc : __pageblock_pfn_to_page+0x6c/0x14c
+[ 540.579454] lr : compact_zone+0x994/0x1058
+[ 540.579460] sp : ffffffc03579b510
+[ 540.579463] x29: ffffffc03579b510 x28: 0000000000235800 x27:000000000000000c
+[ 540.579470] x26: 0000000000235c00 x25: 0000000000000068 x24:ffffffc03579b640
+[ 540.579477] x23: 0000000000000001 x22: ffffffc03579b660 x21:0000000000000000
+[ 540.579483] x20: 0000000000235bff x19: ffffffdebf7e3940 x18:ffffffdebf66d140
+[ 540.579489] x17: 00000000739ba063 x16: 00000000739ba063 x15:00000000009f4bff
+[ 540.579495] x14: 0000008000000000 x13: 0000000000000000 x12:0000000000000001
+[ 540.579501] x11: 0000000000000000 x10: 0000000000000000 x9 :ffffff897d2cd440
+[ 540.579507] x8 : 0000000000000000 x7 : 0000000000000000 x6 :ffffffc03579b5b4
+[ 540.579512] x5 : 0000000000027f25 x4 : ffffffc03579b5b8 x3 :0000000000000001
+[ 540.579518] x2 : ffffffdebf7e3940 x1 : 0000000000235c00 x0 :0000000000235800
+[ 540.579524] Call trace:
+[ 540.579527] __pageblock_pfn_to_page+0x6c/0x14c
+[ 540.579533] compact_zone+0x994/0x1058
+[ 540.579536] try_to_compact_pages+0x128/0x378
+[ 540.579540] __alloc_pages_direct_compact+0x80/0x2b0
+[ 540.579544] __alloc_pages_slowpath+0x5c0/0xe10
+[ 540.579547] __alloc_pages+0x250/0x2d0
+[ 540.579550] __iommu_dma_alloc_noncontiguous+0x13c/0x3fc
+[ 540.579561] iommu_dma_alloc+0xa0/0x320
+[ 540.579565] dma_alloc_attrs+0xd4/0x108
+
+[quic_charante@quicinc.com: use kfree_rcu() in place of synchronize_rcu(), per David]
+ Link: https://lkml.kernel.org/r/1698403778-20938-1-git-send-email-quic_charante@quicinc.com
+Link: https://lkml.kernel.org/r/1697202267-23600-1-git-send-email-quic_charante@quicinc.com
+Fixes: f46edbd1b151 ("mm/sparsemem: add helpers track active portions of a section at boot")
+Signed-off-by: Charan Teja Kalla <quic_charante@quicinc.com>
+Cc: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
+Cc: Dan Williams <dan.j.williams@intel.com>
+Cc: David Hildenbrand <david@redhat.com>
+Cc: Mel Gorman <mgorman@techsingularity.net>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/mmzone.h | 14 +++++++++++---
+ mm/sparse.c | 17 +++++++++--------
+ 2 files changed, 20 insertions(+), 11 deletions(-)
+
+diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
+index 9e1485083398..8b8349ffa1cd 100644
+--- a/include/linux/mmzone.h
++++ b/include/linux/mmzone.h
+@@ -1287,6 +1287,7 @@ static inline unsigned long section_nr_to_pfn(unsigned long sec)
+ #define SUBSECTION_ALIGN_DOWN(pfn) ((pfn) & PAGE_SUBSECTION_MASK)
+
+ struct mem_section_usage {
++ struct rcu_head rcu;
+ #ifdef CONFIG_SPARSEMEM_VMEMMAP
+ DECLARE_BITMAP(subsection_map, SUBSECTIONS_PER_SECTION);
+ #endif
+@@ -1457,7 +1458,7 @@ static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
+ {
+ int idx = subsection_map_index(pfn);
+
+- return test_bit(idx, ms->usage->subsection_map);
++ return test_bit(idx, READ_ONCE(ms->usage)->subsection_map);
+ }
+ #else
+ static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
+@@ -1481,6 +1482,7 @@ static inline int pfn_section_valid(struct mem_section *ms, unsigned long pfn)
+ static inline int pfn_valid(unsigned long pfn)
+ {
+ struct mem_section *ms;
++ int ret;
+
+ /*
+ * Ensure the upper PAGE_SHIFT bits are clear in the
+@@ -1494,13 +1496,19 @@ static inline int pfn_valid(unsigned long pfn)
+ if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
+ return 0;
+ ms = __pfn_to_section(pfn);
+- if (!valid_section(ms))
++ rcu_read_lock();
++ if (!valid_section(ms)) {
++ rcu_read_unlock();
+ return 0;
++ }
+ /*
+ * Traditionally early sections always returned pfn_valid() for
+ * the entire section-sized span.
+ */
+- return early_section(ms) || pfn_section_valid(ms, pfn);
++ ret = early_section(ms) || pfn_section_valid(ms, pfn);
++ rcu_read_unlock();
++
++ return ret;
+ }
+ #endif
+
+diff --git a/mm/sparse.c b/mm/sparse.c
+index 120bc8ea5293..27092badd15b 100644
+--- a/mm/sparse.c
++++ b/mm/sparse.c
+@@ -789,6 +789,13 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
+ if (empty) {
+ unsigned long section_nr = pfn_to_section_nr(pfn);
+
++ /*
++ * Mark the section invalid so that valid_section()
++ * return false. This prevents code from dereferencing
++ * ms->usage array.
++ */
++ ms->section_mem_map &= ~SECTION_HAS_MEM_MAP;
++
+ /*
+ * When removing an early section, the usage map is kept (as the
+ * usage maps of other sections fall into the same page). It
+@@ -797,16 +804,10 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
+ * was allocated during boot.
+ */
+ if (!PageReserved(virt_to_page(ms->usage))) {
+- kfree(ms->usage);
+- ms->usage = NULL;
++ kfree_rcu(ms->usage, rcu);
++ WRITE_ONCE(ms->usage, NULL);
+ }
+ memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
+- /*
+- * Mark the section invalid so that valid_section()
+- * return false. This prevents code from dereferencing
+- * ms->usage array.
+- */
+- ms->section_mem_map &= ~SECTION_HAS_MEM_MAP;
+ }
+
+ /*
+--
+2.43.0
+
--- /dev/null
+From dfd6261dddcc299b40b8d5cbe3e7023f2e295cee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 5 Nov 2021 13:38:15 -0700
+Subject: mm: use __pfn_to_section() instead of open coding it
+
+From: Rolf Eike Beer <eb@emlix.com>
+
+[ Upstream commit f1dc0db296bd25960273649fc6ef2ecbf5aaa0e0 ]
+
+It is defined in the same file just a few lines above.
+
+Link: https://lkml.kernel.org/r/4598487.Rc0NezkW7i@mobilepool36.emlix.com
+Signed-off-by: Rolf Eike Beer <eb@emlix.com>
+Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Stable-dep-of: 5ec8e8ea8b77 ("mm/sparsemem: fix race in accessing memory_section->usage")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/mmzone.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
+index 6ba100216530..9e1485083398 100644
+--- a/include/linux/mmzone.h
++++ b/include/linux/mmzone.h
+@@ -1493,7 +1493,7 @@ static inline int pfn_valid(unsigned long pfn)
+
+ if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
+ return 0;
+- ms = __nr_to_section(pfn_to_section_nr(pfn));
++ ms = __pfn_to_section(pfn);
+ if (!valid_section(ms))
+ return 0;
+ /*
+@@ -1508,7 +1508,7 @@ static inline int pfn_in_present_section(unsigned long pfn)
+ {
+ if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
+ return 0;
+- return present_section(__nr_to_section(pfn_to_section_nr(pfn)));
++ return present_section(__pfn_to_section(pfn));
+ }
+
+ static inline unsigned long next_present_section_nr(unsigned long section_nr)
+--
+2.43.0
+
--- /dev/null
+From bfc7f89d24d6164689aed7061a97879ef05fd861 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 22 May 2022 12:34:38 -0400
+Subject: NFSD: Add documenting comment for nfsd4_release_lockowner()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 043862b09cc00273e35e6c3a6389957953a34207 ]
+
+And return explicit nfserr values that match what is documented in the
+new comment / API contract.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: edcf9725150e ("nfsd: fix RELEASE_LOCKOWNER")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs4state.c | 23 ++++++++++++++++++++---
+ 1 file changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 798063b9b96f..f8533299db1c 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -7284,6 +7284,23 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+ return status;
+ }
+
++/**
++ * nfsd4_release_lockowner - process NFSv4.0 RELEASE_LOCKOWNER operations
++ * @rqstp: RPC transaction
++ * @cstate: NFSv4 COMPOUND state
++ * @u: RELEASE_LOCKOWNER arguments
++ *
++ * The lockowner's so_count is bumped when a lock record is added
++ * or when copying a conflicting lock. The latter case is brief,
++ * but can lead to fleeting false positives when looking for
++ * locks-in-use.
++ *
++ * Return values:
++ * %nfs_ok: lockowner released or not found
++ * %nfserr_locks_held: lockowner still in use
++ * %nfserr_stale_clientid: clientid no longer active
++ * %nfserr_expired: clientid not recognized
++ */
+ __be32
+ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+@@ -7310,7 +7327,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner);
+ if (!lo) {
+ spin_unlock(&clp->cl_lock);
+- return status;
++ return nfs_ok;
+ }
+ if (atomic_read(&lo->lo_owner.so_count) != 2) {
+ spin_unlock(&clp->cl_lock);
+@@ -7326,11 +7343,11 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ put_ol_stateid_locked(stp, &reaplist);
+ }
+ spin_unlock(&clp->cl_lock);
++
+ free_ol_stateid_reaplist(&reaplist);
+ remove_blocked_locks(lo);
+ nfs4_put_stateowner(&lo->lo_owner);
+-
+- return status;
++ return nfs_ok;
+ }
+
+ static inline struct nfs4_client_reclaim *
+--
+2.43.0
+
--- /dev/null
+From b99447c0e88afdb26e8907c0904190f6064f4f1b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 22 Jan 2024 14:58:16 +1100
+Subject: nfsd: fix RELEASE_LOCKOWNER
+
+From: NeilBrown <neilb@suse.de>
+
+[ Upstream commit edcf9725150e42beeca42d085149f4c88fa97afd ]
+
+The test on so_count in nfsd4_release_lockowner() is nonsense and
+harmful. Revert to using check_for_locks(), changing that to not sleep.
+
+First: harmful.
+As is documented in the kdoc comment for nfsd4_release_lockowner(), the
+test on so_count can transiently return a false positive resulting in a
+return of NFS4ERR_LOCKS_HELD when in fact no locks are held. This is
+clearly a protocol violation and with the Linux NFS client it can cause
+incorrect behaviour.
+
+If RELEASE_LOCKOWNER is sent while some other thread is still
+processing a LOCK request which failed because, at the time that request
+was received, the given owner held a conflicting lock, then the nfsd
+thread processing that LOCK request can hold a reference (conflock) to
+the lock owner that causes nfsd4_release_lockowner() to return an
+incorrect error.
+
+The Linux NFS client ignores that NFS4ERR_LOCKS_HELD error because it
+never sends NFS4_RELEASE_LOCKOWNER without first releasing any locks, so
+it knows that the error is impossible. It assumes the lock owner was in
+fact released so it feels free to use the same lock owner identifier in
+some later locking request.
+
+When it does reuse a lock owner identifier for which a previous RELEASE
+failed, it will naturally use a lock_seqid of zero. However the server,
+which didn't release the lock owner, will expect a larger lock_seqid and
+so will respond with NFS4ERR_BAD_SEQID.
+
+So clearly it is harmful to allow a false positive, which testing
+so_count allows.
+
+The test is nonsense because ... well... it doesn't mean anything.
+
+so_count is the sum of three different counts.
+1/ the set of states listed on so_stateids
+2/ the set of active vfs locks owned by any of those states
+3/ various transient counts such as for conflicting locks.
+
+When it is tested against '2' it is clear that one of these is the
+transient reference obtained by find_lockowner_str_locked(). It is not
+clear what the other one is expected to be.
+
+In practice, the count is often 2 because there is precisely one state
+on so_stateids. If there were more, this would fail.
+
+In my testing I see two circumstances when RELEASE_LOCKOWNER is called.
+In one case, CLOSE is called before RELEASE_LOCKOWNER. That results in
+all the lock states being removed, and so the lockowner being discarded
+(it is removed when there are no more references which usually happens
+when the lock state is discarded). When nfsd4_release_lockowner() finds
+that the lock owner doesn't exist, it returns success.
+
+The other case shows an so_count of '2' and precisely one state listed
+in so_stateid. It appears that the Linux client uses a separate lock
+owner for each file resulting in one lock state per lock owner, so this
+test on '2' is safe. For another client it might not be safe.
+
+So this patch changes check_for_locks() to use the (newish)
+find_any_file_locked() so that it doesn't take a reference on the
+nfs4_file and so never calls nfsd_file_put(), and so never sleeps. With
+this check is it safe to restore the use of check_for_locks() rather
+than testing so_count against the mysterious '2'.
+
+Fixes: ce3c4ad7f4ce ("NFSD: Fix possible sleep during nfsd4_release_lockowner()")
+Signed-off-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Cc: stable@vger.kernel.org # v6.2+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs4state.c | 26 +++++++++++++++-----------
+ 1 file changed, 15 insertions(+), 11 deletions(-)
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index f8533299db1c..07ea35803629 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -7257,14 +7257,16 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+ {
+ struct file_lock *fl;
+ int status = false;
+- struct nfsd_file *nf = find_any_file(fp);
++ struct nfsd_file *nf;
+ struct inode *inode;
+ struct file_lock_context *flctx;
+
++ spin_lock(&fp->fi_lock);
++ nf = find_any_file_locked(fp);
+ if (!nf) {
+ /* Any valid lock stateid should have some sort of access */
+ WARN_ON_ONCE(1);
+- return status;
++ goto out;
+ }
+
+ inode = locks_inode(nf->nf_file);
+@@ -7280,7 +7282,8 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+ }
+ spin_unlock(&flctx->flc_lock);
+ }
+- nfsd_file_put(nf);
++out:
++ spin_unlock(&fp->fi_lock);
+ return status;
+ }
+
+@@ -7290,10 +7293,8 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner)
+ * @cstate: NFSv4 COMPOUND state
+ * @u: RELEASE_LOCKOWNER arguments
+ *
+- * The lockowner's so_count is bumped when a lock record is added
+- * or when copying a conflicting lock. The latter case is brief,
+- * but can lead to fleeting false positives when looking for
+- * locks-in-use.
++ * Check if theree are any locks still held and if not - free the lockowner
++ * and any lock state that is owned.
+ *
+ * Return values:
+ * %nfs_ok: lockowner released or not found
+@@ -7329,10 +7330,13 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ spin_unlock(&clp->cl_lock);
+ return nfs_ok;
+ }
+- if (atomic_read(&lo->lo_owner.so_count) != 2) {
+- spin_unlock(&clp->cl_lock);
+- nfs4_put_stateowner(&lo->lo_owner);
+- return nfserr_locks_held;
++
++ list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) {
++ if (check_for_locks(stp->st_stid.sc_file, lo)) {
++ spin_unlock(&clp->cl_lock);
++ nfs4_put_stateowner(&lo->lo_owner);
++ return nfserr_locks_held;
++ }
+ }
+ unhash_lockowner_locked(lo);
+ while (!list_empty(&lo->lo_owner.so_stateids)) {
+--
+2.43.0
+
--- /dev/null
+From 05aaa4892314880beb9474adeb0dd95d3b8086ad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 22 May 2022 12:07:18 -0400
+Subject: NFSD: Modernize nfsd4_release_lockowner()
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit bd8fdb6e545f950f4654a9a10d7e819ad48146e5 ]
+
+Refactor: Use existing helpers that other lock operations use. This
+change removes several automatic variables, so re-organize the
+variable declarations for readability.
+
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: edcf9725150e ("nfsd: fix RELEASE_LOCKOWNER")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfsd/nfs4state.c | 36 +++++++++++-------------------------
+ 1 file changed, 11 insertions(+), 25 deletions(-)
+
+diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
+index 9b660491f393..798063b9b96f 100644
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -7290,16 +7290,13 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ union nfsd4_op_u *u)
+ {
+ struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
++ struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+ clientid_t *clid = &rlockowner->rl_clientid;
+- struct nfs4_stateowner *sop;
+- struct nfs4_lockowner *lo = NULL;
+ struct nfs4_ol_stateid *stp;
+- struct xdr_netobj *owner = &rlockowner->rl_owner;
+- unsigned int hashval = ownerstr_hashval(owner);
+- __be32 status;
+- struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
++ struct nfs4_lockowner *lo;
+ struct nfs4_client *clp;
+- LIST_HEAD (reaplist);
++ LIST_HEAD(reaplist);
++ __be32 status;
+
+ dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
+ clid->cl_boot, clid->cl_id);
+@@ -7307,30 +7304,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
+ status = set_client(clid, cstate, nn);
+ if (status)
+ return status;
+-
+ clp = cstate->clp;
+- /* Find the matching lock stateowner */
+- spin_lock(&clp->cl_lock);
+- list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval],
+- so_strhash) {
+
+- if (sop->so_is_open_owner || !same_owner_str(sop, owner))
+- continue;
+-
+- if (atomic_read(&sop->so_count) != 1) {
+- spin_unlock(&clp->cl_lock);
+- return nfserr_locks_held;
+- }
+-
+- lo = lockowner(sop);
+- nfs4_get_stateowner(sop);
+- break;
+- }
++ spin_lock(&clp->cl_lock);
++ lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner);
+ if (!lo) {
+ spin_unlock(&clp->cl_lock);
+ return status;
+ }
+-
++ if (atomic_read(&lo->lo_owner.so_count) != 2) {
++ spin_unlock(&clp->cl_lock);
++ nfs4_put_stateowner(&lo->lo_owner);
++ return nfserr_locks_held;
++ }
+ unhash_lockowner_locked(lo);
+ while (!list_empty(&lo->lo_owner.so_stateids)) {
+ stp = list_first_entry(&lo->lo_owner.so_stateids,
+--
+2.43.0
+
--- /dev/null
+From 5b7b64f163aaa80fab411ec73cbb0e94e184e90b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Dec 2023 11:11:28 +0100
+Subject: pipe: wakeup wr_wait after setting max_usage
+
+From: Lukas Schauer <lukas@schauer.dev>
+
+[ Upstream commit e95aada4cb93d42e25c30a0ef9eb2923d9711d4a ]
+
+Commit c73be61cede5 ("pipe: Add general notification queue support") a
+regression was introduced that would lock up resized pipes under certain
+conditions. See the reproducer in [1].
+
+The commit resizing the pipe ring size was moved to a different
+function, doing that moved the wakeup for pipe->wr_wait before actually
+raising pipe->max_usage. If a pipe was full before the resize occured it
+would result in the wakeup never actually triggering pipe_write.
+
+Set @max_usage and @nr_accounted before waking writers if this isn't a
+watch queue.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=212295 [1]
+Link: https://lore.kernel.org/r/20231201-orchideen-modewelt-e009de4562c6@brauner
+Fixes: c73be61cede5 ("pipe: Add general notification queue support")
+Reviewed-by: David Howells <dhowells@redhat.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Lukas Schauer <lukas@schauer.dev>
+[Christian Brauner <brauner@kernel.org>: rewrite to account for watch queues]
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/pipe.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/fs/pipe.c b/fs/pipe.c
+index 1a43948c0c36..a8b8ef2dae7b 100644
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -1300,6 +1300,11 @@ int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots)
+ pipe->tail = tail;
+ pipe->head = head;
+
++ if (!pipe_has_watch_queue(pipe)) {
++ pipe->max_usage = nr_slots;
++ pipe->nr_accounted = nr_slots;
++ }
++
+ spin_unlock_irq(&pipe->rd_wait.lock);
+
+ /* This might have made more room for writers */
+@@ -1351,8 +1356,6 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
+ if (ret < 0)
+ goto out_revert_acct;
+
+- pipe->max_usage = nr_slots;
+- pipe->nr_accounted = nr_slots;
+ return pipe->max_usage * PAGE_SIZE;
+
+ out_revert_acct:
+--
+2.43.0
+
--- /dev/null
+From bf88a10594f21c21887f67a3a71aec20d58c99ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 26 Mar 2023 06:19:35 +0800
+Subject: PM: core: Remove unnecessary (void *) conversions
+
+From: Li zeming <zeming@nfschina.com>
+
+[ Upstream commit 73d73f5ee7fb0c42ff87091d105bee720a9565f1 ]
+
+Assignments from pointer variables of type (void *) do not require
+explicit type casts, so remove such type cases from the code in
+drivers/base/power/main.c where applicable.
+
+Signed-off-by: Li zeming <zeming@nfschina.com>
+[ rjw: Subject and changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Stable-dep-of: 7839d0078e0d ("PM: sleep: Fix possible deadlocks in core system-wide PM code")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/power/main.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
+index 8c4819fe73d4..b4cd003d3e39 100644
+--- a/drivers/base/power/main.c
++++ b/drivers/base/power/main.c
+@@ -680,7 +680,7 @@ static bool dpm_async_fn(struct device *dev, async_func_t func)
+
+ static void async_resume_noirq(void *data, async_cookie_t cookie)
+ {
+- struct device *dev = (struct device *)data;
++ struct device *dev = data;
+ int error;
+
+ error = device_resume_noirq(dev, pm_transition, true);
+@@ -819,7 +819,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
+
+ static void async_resume_early(void *data, async_cookie_t cookie)
+ {
+- struct device *dev = (struct device *)data;
++ struct device *dev = data;
+ int error;
+
+ error = device_resume_early(dev, pm_transition, true);
+@@ -983,7 +983,7 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
+
+ static void async_resume(void *data, async_cookie_t cookie)
+ {
+- struct device *dev = (struct device *)data;
++ struct device *dev = data;
+ int error;
+
+ error = device_resume(dev, pm_transition, true);
+@@ -1272,7 +1272,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
+
+ static void async_suspend_noirq(void *data, async_cookie_t cookie)
+ {
+- struct device *dev = (struct device *)data;
++ struct device *dev = data;
+ int error;
+
+ error = __device_suspend_noirq(dev, pm_transition, true);
+@@ -1455,7 +1455,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
+
+ static void async_suspend_late(void *data, async_cookie_t cookie)
+ {
+- struct device *dev = (struct device *)data;
++ struct device *dev = data;
+ int error;
+
+ error = __device_suspend_late(dev, pm_transition, true);
+@@ -1731,7 +1731,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
+
+ static void async_suspend(void *data, async_cookie_t cookie)
+ {
+- struct device *dev = (struct device *)data;
++ struct device *dev = data;
+ int error;
+
+ error = __device_suspend(dev, pm_transition, true);
+--
+2.43.0
+
--- /dev/null
+From 2fb24f0d287f9cf2db2cd73f41dba8b5a6710453 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Mar 2021 15:58:21 +0900
+Subject: PM / devfreq: Add cpu based scaling support to passive governor
+
+From: Saravana Kannan <skannan@codeaurora.org>
+
+[ Upstream commit a03dacb0316f74400846aaf144d6c73f4217ca08 ]
+
+Many CPU architectures have caches that can scale independent of the
+CPUs. Frequency scaling of the caches is necessary to make sure that the
+cache is not a performance bottleneck that leads to poor performance and
+power. The same idea applies for RAM/DDR.
+
+To achieve this, this patch adds support for cpu based scaling to the
+passive governor. This is accomplished by taking the current frequency
+of each CPU frequency domain and then adjust the frequency of the cache
+(or any devfreq device) based on the frequency of the CPUs. It listens
+to CPU frequency transition notifiers to keep itself up to date on the
+current CPU frequency.
+
+To decide the frequency of the device, the governor does one of the
+following:
+* Derives the optimal devfreq device opp from required-opps property of
+ the parent cpu opp_table.
+
+* Scales the device frequency in proportion to the CPU frequency. So, if
+ the CPUs are running at their max frequency, the device runs at its
+ max frequency. If the CPUs are running at their min frequency, the
+ device runs at its min frequency. It is interpolated for frequencies
+ in between.
+
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Johnson Wang <johnson.wang@mediatek.com>
+Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
+[Sibi: Integrated cpu-freqmap governor into passive_governor]
+Signed-off-by: Sibi Sankar <sibis@codeaurora.org>
+[Chanwoo: Fix conflict with latest code and cleanup code]
+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
+Stable-dep-of: 08e23d05fa6d ("PM / devfreq: Fix buffer overflow in trans_stat_show")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/devfreq/governor.h | 22 +++
+ drivers/devfreq/governor_passive.c | 298 +++++++++++++++++++++++++++--
+ include/linux/devfreq.h | 17 +-
+ 3 files changed, 323 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
+index 9a9495f94ac6..3c36c92c89a9 100644
+--- a/drivers/devfreq/governor.h
++++ b/drivers/devfreq/governor.h
+@@ -47,6 +47,28 @@
+ #define DEVFREQ_GOV_ATTR_POLLING_INTERVAL BIT(0)
+ #define DEVFREQ_GOV_ATTR_TIMER BIT(1)
+
++/**
++ * struct devfreq_cpu_data - Hold the per-cpu data
++ * @dev: reference to cpu device.
++ * @first_cpu: the cpumask of the first cpu of a policy.
++ * @opp_table: reference to cpu opp table.
++ * @cur_freq: the current frequency of the cpu.
++ * @min_freq: the min frequency of the cpu.
++ * @max_freq: the max frequency of the cpu.
++ *
++ * This structure stores the required cpu_data of a cpu.
++ * This is auto-populated by the governor.
++ */
++struct devfreq_cpu_data {
++ struct device *dev;
++ unsigned int first_cpu;
++
++ struct opp_table *opp_table;
++ unsigned int cur_freq;
++ unsigned int min_freq;
++ unsigned int max_freq;
++};
++
+ /**
+ * struct devfreq_governor - Devfreq policy governor
+ * @node: list node - contains registered devfreq governors
+diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
+index fc09324a03e0..7f30088b500b 100644
+--- a/drivers/devfreq/governor_passive.c
++++ b/drivers/devfreq/governor_passive.c
+@@ -8,11 +8,85 @@
+ */
+
+ #include <linux/module.h>
++#include <linux/cpu.h>
++#include <linux/cpufreq.h>
++#include <linux/cpumask.h>
++#include <linux/slab.h>
+ #include <linux/device.h>
+ #include <linux/devfreq.h>
+ #include "governor.h"
+
+-static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
++#define HZ_PER_KHZ 1000
++
++static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
++ struct opp_table *p_opp_table,
++ struct opp_table *opp_table,
++ unsigned long *freq)
++{
++ struct dev_pm_opp *opp = NULL, *p_opp = NULL;
++ unsigned long target_freq;
++
++ if (!p_dev || !p_opp_table || !opp_table || !freq)
++ return 0;
++
++ p_opp = devfreq_recommended_opp(p_dev, freq, 0);
++ if (IS_ERR(p_opp))
++ return 0;
++
++ opp = dev_pm_opp_xlate_required_opp(p_opp_table, opp_table, p_opp);
++ dev_pm_opp_put(p_opp);
++
++ if (IS_ERR(opp))
++ return 0;
++
++ target_freq = dev_pm_opp_get_freq(opp);
++ dev_pm_opp_put(opp);
++
++ return target_freq;
++}
++
++static int get_target_freq_with_cpufreq(struct devfreq *devfreq,
++ unsigned long *target_freq)
++{
++ struct devfreq_passive_data *p_data =
++ (struct devfreq_passive_data *)devfreq->data;
++ struct devfreq_cpu_data *parent_cpu_data;
++ unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent;
++ unsigned long dev_min, dev_max;
++ unsigned long freq = 0;
++
++ for_each_online_cpu(cpu) {
++ parent_cpu_data = p_data->parent_cpu_data[cpu];
++ if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu)
++ continue;
++
++ /* Get target freq via required opps */
++ cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ;
++ freq = get_target_freq_by_required_opp(parent_cpu_data->dev,
++ parent_cpu_data->opp_table,
++ devfreq->opp_table, &cpu_cur);
++ if (freq) {
++ *target_freq = max(freq, *target_freq);
++ continue;
++ }
++
++ /* Use interpolation if required opps is not available */
++ devfreq_get_freq_range(devfreq, &dev_min, &dev_max);
++
++ cpu_min = parent_cpu_data->min_freq;
++ cpu_max = parent_cpu_data->max_freq;
++ cpu_cur = parent_cpu_data->cur_freq;
++
++ cpu_percent = ((cpu_cur - cpu_min) * 100) / (cpu_max - cpu_min);
++ freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100);
++
++ *target_freq = max(freq, *target_freq);
++ }
++
++ return 0;
++}
++
++static int get_target_freq_with_devfreq(struct devfreq *devfreq,
+ unsigned long *freq)
+ {
+ struct devfreq_passive_data *p_data
+@@ -99,6 +173,181 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
+ return 0;
+ }
+
++static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
++ unsigned long *freq)
++{
++ struct devfreq_passive_data *p_data =
++ (struct devfreq_passive_data *)devfreq->data;
++ int ret;
++
++ if (!p_data)
++ return -EINVAL;
++
++ /*
++ * If the devfreq device with passive governor has the specific method
++ * to determine the next frequency, should use the get_target_freq()
++ * of struct devfreq_passive_data.
++ */
++ if (p_data->get_target_freq)
++ return p_data->get_target_freq(devfreq, freq);
++
++ switch (p_data->parent_type) {
++ case DEVFREQ_PARENT_DEV:
++ ret = get_target_freq_with_devfreq(devfreq, freq);
++ break;
++ case CPUFREQ_PARENT_DEV:
++ ret = get_target_freq_with_cpufreq(devfreq, freq);
++ break;
++ default:
++ ret = -EINVAL;
++ dev_err(&devfreq->dev, "Invalid parent type\n");
++ break;
++ }
++
++ return ret;
++}
++
++static int cpufreq_passive_notifier_call(struct notifier_block *nb,
++ unsigned long event, void *ptr)
++{
++ struct devfreq_passive_data *p_data =
++ container_of(nb, struct devfreq_passive_data, nb);
++ struct devfreq *devfreq = (struct devfreq *)p_data->this;
++ struct devfreq_cpu_data *parent_cpu_data;
++ struct cpufreq_freqs *freqs = ptr;
++ unsigned int cur_freq;
++ int ret;
++
++ if (event != CPUFREQ_POSTCHANGE || !freqs ||
++ !p_data->parent_cpu_data[freqs->policy->cpu])
++ return 0;
++
++ parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu];
++ if (parent_cpu_data->cur_freq == freqs->new)
++ return 0;
++
++ cur_freq = parent_cpu_data->cur_freq;
++ parent_cpu_data->cur_freq = freqs->new;
++
++ mutex_lock(&devfreq->lock);
++ ret = devfreq_update_target(devfreq, freqs->new);
++ mutex_unlock(&devfreq->lock);
++ if (ret) {
++ parent_cpu_data->cur_freq = cur_freq;
++ dev_err(&devfreq->dev, "failed to update the frequency.\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
++{
++ struct devfreq_passive_data *p_data
++ = (struct devfreq_passive_data *)devfreq->data;
++ struct devfreq_cpu_data *parent_cpu_data;
++ int cpu, ret;
++
++ if (p_data->nb.notifier_call) {
++ ret = cpufreq_unregister_notifier(&p_data->nb,
++ CPUFREQ_TRANSITION_NOTIFIER);
++ if (ret < 0)
++ return ret;
++ }
++
++ for_each_possible_cpu(cpu) {
++ parent_cpu_data = p_data->parent_cpu_data[cpu];
++ if (!parent_cpu_data)
++ continue;
++
++ if (parent_cpu_data->opp_table)
++ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
++ kfree(parent_cpu_data);
++ }
++
++ return 0;
++}
++
++static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
++{
++ struct devfreq_passive_data *p_data
++ = (struct devfreq_passive_data *)devfreq->data;
++ struct device *dev = devfreq->dev.parent;
++ struct opp_table *opp_table = NULL;
++ struct devfreq_cpu_data *parent_cpu_data;
++ struct cpufreq_policy *policy;
++ struct device *cpu_dev;
++ unsigned int cpu;
++ int ret;
++
++ p_data->nb.notifier_call = cpufreq_passive_notifier_call;
++ ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER);
++ if (ret) {
++ dev_err(dev, "failed to register cpufreq notifier\n");
++ p_data->nb.notifier_call = NULL;
++ goto err;
++ }
++
++ for_each_possible_cpu(cpu) {
++ if (p_data->parent_cpu_data[cpu])
++ continue;
++
++ policy = cpufreq_cpu_get(cpu);
++ if (!policy) {
++ ret = -EPROBE_DEFER;
++ goto err;
++ }
++
++ parent_cpu_data = kzalloc(sizeof(*parent_cpu_data),
++ GFP_KERNEL);
++ if (!parent_cpu_data) {
++ ret = -ENOMEM;
++ goto err_put_policy;
++ }
++
++ cpu_dev = get_cpu_device(cpu);
++ if (!cpu_dev) {
++ dev_err(dev, "failed to get cpu device\n");
++ ret = -ENODEV;
++ goto err_free_cpu_data;
++ }
++
++ opp_table = dev_pm_opp_get_opp_table(cpu_dev);
++ if (IS_ERR(opp_table)) {
++ dev_err(dev, "failed to get opp_table of cpu%d\n", cpu);
++ ret = PTR_ERR(opp_table);
++ goto err_free_cpu_data;
++ }
++
++ parent_cpu_data->dev = cpu_dev;
++ parent_cpu_data->opp_table = opp_table;
++ parent_cpu_data->first_cpu = cpumask_first(policy->related_cpus);
++ parent_cpu_data->cur_freq = policy->cur;
++ parent_cpu_data->min_freq = policy->cpuinfo.min_freq;
++ parent_cpu_data->max_freq = policy->cpuinfo.max_freq;
++
++ p_data->parent_cpu_data[cpu] = parent_cpu_data;
++ cpufreq_cpu_put(policy);
++ }
++
++ mutex_lock(&devfreq->lock);
++ ret = devfreq_update_target(devfreq, 0L);
++ mutex_unlock(&devfreq->lock);
++ if (ret)
++ dev_err(dev, "failed to update the frequency\n");
++
++ return ret;
++
++err_free_cpu_data:
++ kfree(parent_cpu_data);
++err_put_policy:
++ cpufreq_cpu_put(policy);
++err:
++ WARN_ON(cpufreq_passive_unregister_notifier(devfreq));
++
++ return ret;
++}
++
+ static int devfreq_passive_notifier_call(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+ {
+@@ -131,30 +380,55 @@ static int devfreq_passive_notifier_call(struct notifier_block *nb,
+ return NOTIFY_DONE;
+ }
+
+-static int devfreq_passive_event_handler(struct devfreq *devfreq,
+- unsigned int event, void *data)
++static int devfreq_passive_unregister_notifier(struct devfreq *devfreq)
++{
++ struct devfreq_passive_data *p_data
++ = (struct devfreq_passive_data *)devfreq->data;
++ struct devfreq *parent = (struct devfreq *)p_data->parent;
++ struct notifier_block *nb = &p_data->nb;
++
++ return devfreq_unregister_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER);
++}
++
++static int devfreq_passive_register_notifier(struct devfreq *devfreq)
+ {
+ struct devfreq_passive_data *p_data
+ = (struct devfreq_passive_data *)devfreq->data;
+ struct devfreq *parent = (struct devfreq *)p_data->parent;
+ struct notifier_block *nb = &p_data->nb;
+- int ret = 0;
+
+ if (!parent)
+ return -EPROBE_DEFER;
+
++ nb->notifier_call = devfreq_passive_notifier_call;
++ return devfreq_register_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER);
++}
++
++static int devfreq_passive_event_handler(struct devfreq *devfreq,
++ unsigned int event, void *data)
++{
++ struct devfreq_passive_data *p_data
++ = (struct devfreq_passive_data *)devfreq->data;
++ int ret = -EINVAL;
++
++ if (!p_data)
++ return -EINVAL;
++
++ if (!p_data->this)
++ p_data->this = devfreq;
++
+ switch (event) {
+ case DEVFREQ_GOV_START:
+- if (!p_data->this)
+- p_data->this = devfreq;
+-
+- nb->notifier_call = devfreq_passive_notifier_call;
+- ret = devfreq_register_notifier(parent, nb,
+- DEVFREQ_TRANSITION_NOTIFIER);
++ if (p_data->parent_type == DEVFREQ_PARENT_DEV)
++ ret = devfreq_passive_register_notifier(devfreq);
++ else if (p_data->parent_type == CPUFREQ_PARENT_DEV)
++ ret = cpufreq_passive_register_notifier(devfreq);
+ break;
+ case DEVFREQ_GOV_STOP:
+- WARN_ON(devfreq_unregister_notifier(parent, nb,
+- DEVFREQ_TRANSITION_NOTIFIER));
++ if (p_data->parent_type == DEVFREQ_PARENT_DEV)
++ WARN_ON(devfreq_passive_unregister_notifier(devfreq));
++ else if (p_data->parent_type == CPUFREQ_PARENT_DEV)
++ WARN_ON(cpufreq_passive_unregister_notifier(devfreq));
+ break;
+ default:
+ break;
+diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
+index d94b9ed9443e..86ef2885c04b 100644
+--- a/include/linux/devfreq.h
++++ b/include/linux/devfreq.h
+@@ -38,6 +38,7 @@ enum devfreq_timer {
+
+ struct devfreq;
+ struct devfreq_governor;
++struct devfreq_cpu_data;
+ struct thermal_cooling_device;
+
+ /**
+@@ -289,6 +290,11 @@ struct devfreq_simple_ondemand_data {
+ #endif
+
+ #if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
++enum devfreq_parent_dev_type {
++ DEVFREQ_PARENT_DEV,
++ CPUFREQ_PARENT_DEV,
++};
++
+ /**
+ * struct devfreq_passive_data - ``void *data`` fed to struct devfreq
+ * and devfreq_add_device
+@@ -300,8 +306,11 @@ struct devfreq_simple_ondemand_data {
+ * using governors except for passive governor.
+ * If the devfreq device has the specific method to decide
+ * the next frequency, should use this callback.
+- * @this: the devfreq instance of own device.
+- * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER list
++ * @parent_type: the parent type of the device.
++ * @this: the devfreq instance of own device.
++ * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or
++ * CPUFREQ_TRANSITION_NOTIFIER list.
++ * @parent_cpu_data: the state min/max/current frequency of all online cpu's.
+ *
+ * The devfreq_passive_data have to set the devfreq instance of parent
+ * device with governors except for the passive governor. But, don't need to
+@@ -315,9 +324,13 @@ struct devfreq_passive_data {
+ /* Optional callback to decide the next frequency of passvice device */
+ int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
+
++ /* Should set the type of parent device */
++ enum devfreq_parent_dev_type parent_type;
++
+ /* For passive governor's internal use. Don't need to set them */
+ struct devfreq *this;
+ struct notifier_block nb;
++ struct devfreq_cpu_data *parent_cpu_data[NR_CPUS];
+ };
+ #endif
+
+--
+2.43.0
+
--- /dev/null
+From 7cde1179118a6f4e0ea429fd4bb6659165ba0a96 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Mar 2021 02:07:29 +0900
+Subject: PM / devfreq: Export devfreq_get_freq_range symbol within devfreq
+
+From: Chanwoo Choi <cw00.choi@samsung.com>
+
+[ Upstream commit 713472e53e6e53c985e283782b0fd76b8ecfd47e ]
+
+In order to get frequency range within devfreq governors,
+export devfreq_get_freq_range symbol within devfreq.
+
+Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Johnson Wang <johnson.wang@mediatek.com>
+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
+Stable-dep-of: 08e23d05fa6d ("PM / devfreq: Fix buffer overflow in trans_stat_show")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/devfreq/devfreq.c | 20 ++++++++++++--------
+ drivers/devfreq/governor.h | 2 ++
+ 2 files changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
+index 29a14b0ffe33..c8cee796a5a0 100644
+--- a/drivers/devfreq/devfreq.c
++++ b/drivers/devfreq/devfreq.c
+@@ -112,16 +112,16 @@ static unsigned long find_available_max_freq(struct devfreq *devfreq)
+ }
+
+ /**
+- * get_freq_range() - Get the current freq range
++ * devfreq_get_freq_range() - Get the current freq range
+ * @devfreq: the devfreq instance
+ * @min_freq: the min frequency
+ * @max_freq: the max frequency
+ *
+ * This takes into consideration all constraints.
+ */
+-static void get_freq_range(struct devfreq *devfreq,
+- unsigned long *min_freq,
+- unsigned long *max_freq)
++void devfreq_get_freq_range(struct devfreq *devfreq,
++ unsigned long *min_freq,
++ unsigned long *max_freq)
+ {
+ unsigned long *freq_table = devfreq->profile->freq_table;
+ s32 qos_min_freq, qos_max_freq;
+@@ -158,6 +158,7 @@ static void get_freq_range(struct devfreq *devfreq,
+ if (*min_freq > *max_freq)
+ *min_freq = *max_freq;
+ }
++EXPORT_SYMBOL(devfreq_get_freq_range);
+
+ /**
+ * devfreq_get_freq_level() - Lookup freq_table for the frequency
+@@ -418,7 +419,7 @@ int devfreq_update_target(struct devfreq *devfreq, unsigned long freq)
+ err = devfreq->governor->get_target_freq(devfreq, &freq);
+ if (err)
+ return err;
+- get_freq_range(devfreq, &min_freq, &max_freq);
++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
+
+ if (freq < min_freq) {
+ freq = min_freq;
+@@ -785,6 +786,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
+ {
+ struct devfreq *devfreq;
+ struct devfreq_governor *governor;
++ unsigned long min_freq, max_freq;
+ int err = 0;
+
+ if (!dev || !profile || !governor_name) {
+@@ -849,6 +851,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
+ goto err_dev;
+ }
+
++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
++
+ devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
+ devfreq->opp_table = dev_pm_opp_get_opp_table(dev);
+ if (IS_ERR(devfreq->opp_table))
+@@ -1560,7 +1564,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
+ unsigned long min_freq, max_freq;
+
+ mutex_lock(&df->lock);
+- get_freq_range(df, &min_freq, &max_freq);
++ devfreq_get_freq_range(df, &min_freq, &max_freq);
+ mutex_unlock(&df->lock);
+
+ return sprintf(buf, "%lu\n", min_freq);
+@@ -1614,7 +1618,7 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
+ unsigned long min_freq, max_freq;
+
+ mutex_lock(&df->lock);
+- get_freq_range(df, &min_freq, &max_freq);
++ devfreq_get_freq_range(df, &min_freq, &max_freq);
+ mutex_unlock(&df->lock);
+
+ return sprintf(buf, "%lu\n", max_freq);
+@@ -1928,7 +1932,7 @@ static int devfreq_summary_show(struct seq_file *s, void *data)
+
+ mutex_lock(&devfreq->lock);
+ cur_freq = devfreq->previous_freq;
+- get_freq_range(devfreq, &min_freq, &max_freq);
++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
+ timer = devfreq->profile->timer;
+
+ if (IS_SUPPORTED_ATTR(devfreq->governor->attrs, POLLING_INTERVAL))
+diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
+index 2d69a0ce6291..9a9495f94ac6 100644
+--- a/drivers/devfreq/governor.h
++++ b/drivers/devfreq/governor.h
+@@ -86,6 +86,8 @@ int devfreq_remove_governor(struct devfreq_governor *governor);
+
+ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
+ int devfreq_update_target(struct devfreq *devfreq, unsigned long freq);
++void devfreq_get_freq_range(struct devfreq *devfreq, unsigned long *min_freq,
++ unsigned long *max_freq);
+
+ static inline int devfreq_update_stats(struct devfreq *df)
+ {
+--
+2.43.0
+
--- /dev/null
+From 0ad57c14361cffe2434a4de131b2a24f0898300a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Oct 2023 20:30:15 +0200
+Subject: PM / devfreq: Fix buffer overflow in trans_stat_show
+
+From: Christian Marangi <ansuelsmth@gmail.com>
+
+[ Upstream commit 08e23d05fa6dc4fc13da0ccf09defdd4bbc92ff4 ]
+
+Fix buffer overflow in trans_stat_show().
+
+Convert simple snprintf to the more secure scnprintf with size of
+PAGE_SIZE.
+
+Add condition checking if we are exceeding PAGE_SIZE and exit early from
+loop. Also add at the end a warning that we exceeded PAGE_SIZE and that
+stats is disabled.
+
+Return -EFBIG in the case where we don't have enough space to write the
+full transition table.
+
+Also document in the ABI that this function can return -EFBIG error.
+
+Link: https://lore.kernel.org/all/20231024183016.14648-2-ansuelsmth@gmail.com/
+Cc: stable@vger.kernel.org
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218041
+Fixes: e552bbaf5b98 ("PM / devfreq: Add sysfs node for representing frequency transition information.")
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/ABI/testing/sysfs-class-devfreq | 3 +
+ drivers/devfreq/devfreq.c | 57 +++++++++++++------
+ 2 files changed, 42 insertions(+), 18 deletions(-)
+
+diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
+index 5e6b74f30406..1e7e0bb4c14e 100644
+--- a/Documentation/ABI/testing/sysfs-class-devfreq
++++ b/Documentation/ABI/testing/sysfs-class-devfreq
+@@ -52,6 +52,9 @@ Description:
+
+ echo 0 > /sys/class/devfreq/.../trans_stat
+
++ If the transition table is bigger than PAGE_SIZE, reading
++ this will return an -EFBIG error.
++
+ What: /sys/class/devfreq/.../available_frequencies
+ Date: October 2012
+ Contact: Nishanth Menon <nm@ti.com>
+diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
+index 14b83b8531d7..96dc49c207c7 100644
+--- a/drivers/devfreq/devfreq.c
++++ b/drivers/devfreq/devfreq.c
+@@ -1656,7 +1656,7 @@ static ssize_t trans_stat_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ struct devfreq *df = to_devfreq(dev);
+- ssize_t len;
++ ssize_t len = 0;
+ int i, j;
+ unsigned int max_state;
+
+@@ -1665,7 +1665,7 @@ static ssize_t trans_stat_show(struct device *dev,
+ max_state = df->max_state;
+
+ if (max_state == 0)
+- return sprintf(buf, "Not Supported.\n");
++ return scnprintf(buf, PAGE_SIZE, "Not Supported.\n");
+
+ mutex_lock(&df->lock);
+ if (!df->stop_polling &&
+@@ -1675,31 +1675,52 @@ static ssize_t trans_stat_show(struct device *dev,
+ }
+ mutex_unlock(&df->lock);
+
+- len = sprintf(buf, " From : To\n");
+- len += sprintf(buf + len, " :");
+- for (i = 0; i < max_state; i++)
+- len += sprintf(buf + len, "%10lu",
+- df->freq_table[i]);
++ len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n");
++ len += scnprintf(buf + len, PAGE_SIZE - len, " :");
++ for (i = 0; i < max_state; i++) {
++ if (len >= PAGE_SIZE - 1)
++ break;
++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu",
++ df->freq_table[i]);
++ }
++ if (len >= PAGE_SIZE - 1)
++ return PAGE_SIZE - 1;
+
+- len += sprintf(buf + len, " time(ms)\n");
++ len += scnprintf(buf + len, PAGE_SIZE - len, " time(ms)\n");
+
+ for (i = 0; i < max_state; i++) {
++ if (len >= PAGE_SIZE - 1)
++ break;
+ if (df->freq_table[i] == df->previous_freq)
+- len += sprintf(buf + len, "*");
++ len += scnprintf(buf + len, PAGE_SIZE - len, "*");
+ else
+- len += sprintf(buf + len, " ");
++ len += scnprintf(buf + len, PAGE_SIZE - len, " ");
++ if (len >= PAGE_SIZE - 1)
++ break;
++
++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10lu:",
++ df->freq_table[i]);
++ for (j = 0; j < max_state; j++) {
++ if (len >= PAGE_SIZE - 1)
++ break;
++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10u",
++ df->stats.trans_table[(i * max_state) + j]);
++ }
++ if (len >= PAGE_SIZE - 1)
++ break;
++ len += scnprintf(buf + len, PAGE_SIZE - len, "%10llu\n", (u64)
++ jiffies64_to_msecs(df->stats.time_in_state[i]));
++ }
+
+- len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
+- for (j = 0; j < max_state; j++)
+- len += sprintf(buf + len, "%10u",
+- df->stats.trans_table[(i * max_state) + j]);
++ if (len < PAGE_SIZE - 1)
++ len += scnprintf(buf + len, PAGE_SIZE - len, "Total transition : %u\n",
++ df->stats.total_trans);
+
+- len += sprintf(buf + len, "%10llu\n", (u64)
+- jiffies64_to_msecs(df->stats.time_in_state[i]));
++ if (len >= PAGE_SIZE - 1) {
++ pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n");
++ return -EFBIG;
+ }
+
+- len += sprintf(buf + len, "Total transition : %u\n",
+- df->stats.total_trans);
+ return len;
+ }
+
+--
+2.43.0
+
--- /dev/null
+From 38a1b2738c0915ede2421ea5df780f4ccbc99da0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 Mar 2021 17:22:50 +0900
+Subject: PM / devfreq: passive: Reduce duplicate code when passive_devfreq
+ case
+
+From: Chanwoo Choi <cw00.choi@samsung.com>
+
+[ Upstream commit 05723e71234b60a1a47313ea1a889797ec648f1c ]
+
+In order to keep the consistent coding style between passive_devfreq
+and passive_cpufreq, use common code for handling required opp property.
+Also remove the unneed conditional statement and unify the comment
+of both passive_devfreq and passive_cpufreq when getting the target frequency.
+
+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
+Tested-by: Johnson Wang <johnson.wang@mediatek.com>
+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
+Stable-dep-of: 08e23d05fa6d ("PM / devfreq: Fix buffer overflow in trans_stat_show")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/devfreq/governor_passive.c | 66 ++++--------------------------
+ 1 file changed, 8 insertions(+), 58 deletions(-)
+
+diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
+index 7f30088b500b..ffcce613a48c 100644
+--- a/drivers/devfreq/governor_passive.c
++++ b/drivers/devfreq/governor_passive.c
+@@ -93,65 +93,16 @@ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
+ = (struct devfreq_passive_data *)devfreq->data;
+ struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent;
+ unsigned long child_freq = ULONG_MAX;
+- struct dev_pm_opp *opp, *p_opp;
+ int i, count;
+
+- /*
+- * If the devfreq device with passive governor has the specific method
+- * to determine the next frequency, should use the get_target_freq()
+- * of struct devfreq_passive_data.
+- */
+- if (p_data->get_target_freq)
+- return p_data->get_target_freq(devfreq, freq);
++ /* Get target freq via required opps */
++ child_freq = get_target_freq_by_required_opp(parent_devfreq->dev.parent,
++ parent_devfreq->opp_table,
++ devfreq->opp_table, freq);
++ if (child_freq)
++ goto out;
+
+- /*
+- * If the parent and passive devfreq device uses the OPP table,
+- * get the next frequency by using the OPP table.
+- */
+-
+- /*
+- * - parent devfreq device uses the governors except for passive.
+- * - passive devfreq device uses the passive governor.
+- *
+- * Each devfreq has the OPP table. After deciding the new frequency
+- * from the governor of parent devfreq device, the passive governor
+- * need to get the index of new frequency on OPP table of parent
+- * device. And then the index is used for getting the suitable
+- * new frequency for passive devfreq device.
+- */
+- if (!devfreq->profile || !devfreq->profile->freq_table
+- || devfreq->profile->max_state <= 0)
+- return -EINVAL;
+-
+- /*
+- * The passive governor have to get the correct frequency from OPP
+- * list of parent device. Because in this case, *freq is temporary
+- * value which is decided by ondemand governor.
+- */
+- if (devfreq->opp_table && parent_devfreq->opp_table) {
+- p_opp = devfreq_recommended_opp(parent_devfreq->dev.parent,
+- freq, 0);
+- if (IS_ERR(p_opp))
+- return PTR_ERR(p_opp);
+-
+- opp = dev_pm_opp_xlate_required_opp(parent_devfreq->opp_table,
+- devfreq->opp_table, p_opp);
+- dev_pm_opp_put(p_opp);
+-
+- if (IS_ERR(opp))
+- goto no_required_opp;
+-
+- *freq = dev_pm_opp_get_freq(opp);
+- dev_pm_opp_put(opp);
+-
+- return 0;
+- }
+-
+-no_required_opp:
+- /*
+- * Get the OPP table's index of decided frequency by governor
+- * of parent device.
+- */
++ /* Use interpolation if required opps is not available */
+ for (i = 0; i < parent_devfreq->profile->max_state; i++)
+ if (parent_devfreq->profile->freq_table[i] == *freq)
+ break;
+@@ -159,7 +110,6 @@ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
+ if (i == parent_devfreq->profile->max_state)
+ return -EINVAL;
+
+- /* Get the suitable frequency by using index of parent device. */
+ if (i < devfreq->profile->max_state) {
+ child_freq = devfreq->profile->freq_table[i];
+ } else {
+@@ -167,7 +117,7 @@ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
+ child_freq = devfreq->profile->freq_table[count - 1];
+ }
+
+- /* Return the suitable frequency for passive device. */
++out:
+ *freq = child_freq;
+
+ return 0;
+--
+2.43.0
+
--- /dev/null
+From 648562db5d7b7e518c785b460472ccd2fbdb1ecc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Jun 2022 00:03:51 +0200
+Subject: PM / devfreq: Rework freq_table to be local to devfreq struct
+
+From: Christian Marangi <ansuelsmth@gmail.com>
+
+[ Upstream commit b5d281f6c16dd432b618bdfd36ddba1a58d5b603 ]
+
+On a devfreq PROBE_DEFER, the freq_table in the driver profile struct,
+is never reset and may be leaved in an undefined state.
+
+This comes from the fact that we store the freq_table in the driver
+profile struct that is commonly defined as static and not reset on
+PROBE_DEFER.
+We currently skip the reinit of the freq_table if we found
+it's already defined since a driver may declare his own freq_table.
+
+This logic is flawed in the case devfreq core generate a freq_table, set
+it in the profile struct and then PROBE_DEFER, freeing the freq_table.
+In this case devfreq will found a NOT NULL freq_table that has been
+freed, skip the freq_table generation and probe the driver based on the
+wrong table.
+
+To fix this and correctly handle PROBE_DEFER, use a local freq_table and
+max_state in the devfreq struct and never modify the freq_table present
+in the profile struct if it does provide it.
+
+Fixes: 0ec09ac2cebe ("PM / devfreq: Set the freq_table of devfreq device")
+Cc: stable@vger.kernel.org
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
+Stable-dep-of: 08e23d05fa6d ("PM / devfreq: Fix buffer overflow in trans_stat_show")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/devfreq/devfreq.c | 71 ++++++++++++++----------------
+ drivers/devfreq/governor_passive.c | 14 +++---
+ include/linux/devfreq.h | 5 +++
+ 3 files changed, 46 insertions(+), 44 deletions(-)
+
+diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
+index c8cee796a5a0..14b83b8531d7 100644
+--- a/drivers/devfreq/devfreq.c
++++ b/drivers/devfreq/devfreq.c
+@@ -123,7 +123,7 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
+ unsigned long *min_freq,
+ unsigned long *max_freq)
+ {
+- unsigned long *freq_table = devfreq->profile->freq_table;
++ unsigned long *freq_table = devfreq->freq_table;
+ s32 qos_min_freq, qos_max_freq;
+
+ lockdep_assert_held(&devfreq->lock);
+@@ -133,11 +133,11 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
+ * The devfreq drivers can initialize this in either ascending or
+ * descending order and devfreq core supports both.
+ */
+- if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
++ if (freq_table[0] < freq_table[devfreq->max_state - 1]) {
+ *min_freq = freq_table[0];
+- *max_freq = freq_table[devfreq->profile->max_state - 1];
++ *max_freq = freq_table[devfreq->max_state - 1];
+ } else {
+- *min_freq = freq_table[devfreq->profile->max_state - 1];
++ *min_freq = freq_table[devfreq->max_state - 1];
+ *max_freq = freq_table[0];
+ }
+
+@@ -169,8 +169,8 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
+ {
+ int lev;
+
+- for (lev = 0; lev < devfreq->profile->max_state; lev++)
+- if (freq == devfreq->profile->freq_table[lev])
++ for (lev = 0; lev < devfreq->max_state; lev++)
++ if (freq == devfreq->freq_table[lev])
+ return lev;
+
+ return -EINVAL;
+@@ -178,7 +178,6 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
+
+ static int set_freq_table(struct devfreq *devfreq)
+ {
+- struct devfreq_dev_profile *profile = devfreq->profile;
+ struct dev_pm_opp *opp;
+ unsigned long freq;
+ int i, count;
+@@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq *devfreq)
+ if (count <= 0)
+ return -EINVAL;
+
+- profile->max_state = count;
+- profile->freq_table = devm_kcalloc(devfreq->dev.parent,
+- profile->max_state,
+- sizeof(*profile->freq_table),
+- GFP_KERNEL);
+- if (!profile->freq_table) {
+- profile->max_state = 0;
++ devfreq->max_state = count;
++ devfreq->freq_table = devm_kcalloc(devfreq->dev.parent,
++ devfreq->max_state,
++ sizeof(*devfreq->freq_table),
++ GFP_KERNEL);
++ if (!devfreq->freq_table)
+ return -ENOMEM;
+- }
+
+- for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
++ for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
+ opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
+ if (IS_ERR(opp)) {
+- devm_kfree(devfreq->dev.parent, profile->freq_table);
+- profile->max_state = 0;
++ devm_kfree(devfreq->dev.parent, devfreq->freq_table);
+ return PTR_ERR(opp);
+ }
+ dev_pm_opp_put(opp);
+- profile->freq_table[i] = freq;
++ devfreq->freq_table[i] = freq;
+ }
+
+ return 0;
+@@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
+
+ if (lev != prev_lev) {
+ devfreq->stats.trans_table[
+- (prev_lev * devfreq->profile->max_state) + lev]++;
++ (prev_lev * devfreq->max_state) + lev]++;
+ devfreq->stats.total_trans++;
+ }
+
+@@ -835,6 +831,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
+ if (err < 0)
+ goto err_dev;
+ mutex_lock(&devfreq->lock);
++ } else {
++ devfreq->freq_table = devfreq->profile->freq_table;
++ devfreq->max_state = devfreq->profile->max_state;
+ }
+
+ devfreq->scaling_min_freq = find_available_min_freq(devfreq);
+@@ -870,8 +869,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
+
+ devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
+ array3_size(sizeof(unsigned int),
+- devfreq->profile->max_state,
+- devfreq->profile->max_state),
++ devfreq->max_state,
++ devfreq->max_state),
+ GFP_KERNEL);
+ if (!devfreq->stats.trans_table) {
+ mutex_unlock(&devfreq->lock);
+@@ -880,7 +879,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
+ }
+
+ devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
+- devfreq->profile->max_state,
++ devfreq->max_state,
+ sizeof(*devfreq->stats.time_in_state),
+ GFP_KERNEL);
+ if (!devfreq->stats.time_in_state) {
+@@ -1638,9 +1637,9 @@ static ssize_t available_frequencies_show(struct device *d,
+
+ mutex_lock(&df->lock);
+
+- for (i = 0; i < df->profile->max_state; i++)
++ for (i = 0; i < df->max_state; i++)
+ count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
+- "%lu ", df->profile->freq_table[i]);
++ "%lu ", df->freq_table[i]);
+
+ mutex_unlock(&df->lock);
+ /* Truncate the trailing space */
+@@ -1663,7 +1662,7 @@ static ssize_t trans_stat_show(struct device *dev,
+
+ if (!df->profile)
+ return -EINVAL;
+- max_state = df->profile->max_state;
++ max_state = df->max_state;
+
+ if (max_state == 0)
+ return sprintf(buf, "Not Supported.\n");
+@@ -1680,19 +1679,17 @@ static ssize_t trans_stat_show(struct device *dev,
+ len += sprintf(buf + len, " :");
+ for (i = 0; i < max_state; i++)
+ len += sprintf(buf + len, "%10lu",
+- df->profile->freq_table[i]);
++ df->freq_table[i]);
+
+ len += sprintf(buf + len, " time(ms)\n");
+
+ for (i = 0; i < max_state; i++) {
+- if (df->profile->freq_table[i]
+- == df->previous_freq) {
++ if (df->freq_table[i] == df->previous_freq)
+ len += sprintf(buf + len, "*");
+- } else {
++ else
+ len += sprintf(buf + len, " ");
+- }
+- len += sprintf(buf + len, "%10lu:",
+- df->profile->freq_table[i]);
++
++ len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
+ for (j = 0; j < max_state; j++)
+ len += sprintf(buf + len, "%10u",
+ df->stats.trans_table[(i * max_state) + j]);
+@@ -1716,7 +1713,7 @@ static ssize_t trans_stat_store(struct device *dev,
+ if (!df->profile)
+ return -EINVAL;
+
+- if (df->profile->max_state == 0)
++ if (df->max_state == 0)
+ return count;
+
+ err = kstrtoint(buf, 10, &value);
+@@ -1724,11 +1721,11 @@ static ssize_t trans_stat_store(struct device *dev,
+ return -EINVAL;
+
+ mutex_lock(&df->lock);
+- memset(df->stats.time_in_state, 0, (df->profile->max_state *
++ memset(df->stats.time_in_state, 0, (df->max_state *
+ sizeof(*df->stats.time_in_state)));
+ memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
+- df->profile->max_state,
+- df->profile->max_state));
++ df->max_state,
++ df->max_state));
+ df->stats.total_trans = 0;
+ df->stats.last_update = get_jiffies_64();
+ mutex_unlock(&df->lock);
+diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
+index ffcce613a48c..9997332af3df 100644
+--- a/drivers/devfreq/governor_passive.c
++++ b/drivers/devfreq/governor_passive.c
+@@ -103,18 +103,18 @@ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
+ goto out;
+
+ /* Use interpolation if required opps is not available */
+- for (i = 0; i < parent_devfreq->profile->max_state; i++)
+- if (parent_devfreq->profile->freq_table[i] == *freq)
++ for (i = 0; i < parent_devfreq->max_state; i++)
++ if (parent_devfreq->freq_table[i] == *freq)
+ break;
+
+- if (i == parent_devfreq->profile->max_state)
++ if (i == parent_devfreq->max_state)
+ return -EINVAL;
+
+- if (i < devfreq->profile->max_state) {
+- child_freq = devfreq->profile->freq_table[i];
++ if (i < devfreq->max_state) {
++ child_freq = devfreq->freq_table[i];
+ } else {
+- count = devfreq->profile->max_state;
+- child_freq = devfreq->profile->freq_table[count - 1];
++ count = devfreq->max_state;
++ child_freq = devfreq->freq_table[count - 1];
+ }
+
+ out:
+diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
+index 86ef2885c04b..6084003ea509 100644
+--- a/include/linux/devfreq.h
++++ b/include/linux/devfreq.h
+@@ -148,6 +148,8 @@ struct devfreq_stats {
+ * reevaluate operable frequencies. Devfreq users may use
+ * devfreq.nb to the corresponding register notifier call chain.
+ * @work: delayed work for load monitoring.
++ * @freq_table: current frequency table used by the devfreq driver.
++ * @max_state: count of entry present in the frequency table.
+ * @previous_freq: previously configured frequency value.
+ * @last_status: devfreq user device info, performance statistics
+ * @data: devfreq driver pass to governors, governor should not change it.
+@@ -185,6 +187,9 @@ struct devfreq {
+ struct notifier_block nb;
+ struct delayed_work work;
+
++ unsigned long *freq_table;
++ unsigned int max_state;
++
+ unsigned long previous_freq;
+ struct devfreq_dev_status last_status;
+
+--
+2.43.0
+
--- /dev/null
+From 952ee00ffbbc1090c33acf503238117f089595df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Dec 2023 21:41:06 +0100
+Subject: PM: sleep: Fix possible deadlocks in core system-wide PM code
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 7839d0078e0d5e6cc2fa0b0dfbee71de74f1e557 ]
+
+It is reported that in low-memory situations the system-wide resume core
+code deadlocks, because async_schedule_dev() executes its argument
+function synchronously if it cannot allocate memory (and not only in
+that case) and that function attempts to acquire a mutex that is already
+held. Executing the argument function synchronously from within
+dpm_async_fn() may also be problematic for ordering reasons (it may
+cause a consumer device's resume callback to be invoked before a
+requisite supplier device's one, for example).
+
+Address this by changing the code in question to use
+async_schedule_dev_nocall() for scheduling the asynchronous
+execution of device suspend and resume functions and to directly
+run them synchronously if async_schedule_dev_nocall() returns false.
+
+Link: https://lore.kernel.org/linux-pm/ZYvjiqX6EsL15moe@perf/
+Reported-by: Youngmin Nam <youngmin.nam@samsung.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
+Tested-by: Youngmin Nam <youngmin.nam@samsung.com>
+Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: 5.7+ <stable@vger.kernel.org> # 5.7+: 6aa09a5bccd8 async: Split async_schedule_node_domain()
+Cc: 5.7+ <stable@vger.kernel.org> # 5.7+: 7d4b5d7a37bd async: Introduce async_schedule_dev_nocall()
+Cc: 5.7+ <stable@vger.kernel.org> # 5.7+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/power/main.c | 148 ++++++++++++++++++--------------------
+ 1 file changed, 68 insertions(+), 80 deletions(-)
+
+diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
+index b4cd003d3e39..185ea0d93a5e 100644
+--- a/drivers/base/power/main.c
++++ b/drivers/base/power/main.c
+@@ -580,7 +580,7 @@ bool dev_pm_skip_resume(struct device *dev)
+ }
+
+ /**
+- * device_resume_noirq - Execute a "noirq resume" callback for given device.
++ * __device_resume_noirq - Execute a "noirq resume" callback for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
+ * @async: If true, the device is being resumed asynchronously.
+@@ -588,7 +588,7 @@ bool dev_pm_skip_resume(struct device *dev)
+ * The driver of @dev will not receive interrupts while this function is being
+ * executed.
+ */
+-static int device_resume_noirq(struct device *dev, pm_message_t state, bool async)
++static void __device_resume_noirq(struct device *dev, pm_message_t state, bool async)
+ {
+ pm_callback_t callback = NULL;
+ const char *info = NULL;
+@@ -656,7 +656,13 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
+ Out:
+ complete_all(&dev->power.completion);
+ TRACE_RESUME(error);
+- return error;
++
++ if (error) {
++ suspend_stats.failed_resume_noirq++;
++ dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
++ dpm_save_failed_dev(dev_name(dev));
++ pm_dev_err(dev, state, async ? " async noirq" : " noirq", error);
++ }
+ }
+
+ static bool is_async(struct device *dev)
+@@ -669,11 +675,15 @@ static bool dpm_async_fn(struct device *dev, async_func_t func)
+ {
+ reinit_completion(&dev->power.completion);
+
+- if (is_async(dev)) {
+- get_device(dev);
+- async_schedule_dev(func, dev);
++ if (!is_async(dev))
++ return false;
++
++ get_device(dev);
++
++ if (async_schedule_dev_nocall(func, dev))
+ return true;
+- }
++
++ put_device(dev);
+
+ return false;
+ }
+@@ -681,15 +691,19 @@ static bool dpm_async_fn(struct device *dev, async_func_t func)
+ static void async_resume_noirq(void *data, async_cookie_t cookie)
+ {
+ struct device *dev = data;
+- int error;
+-
+- error = device_resume_noirq(dev, pm_transition, true);
+- if (error)
+- pm_dev_err(dev, pm_transition, " async", error);
+
++ __device_resume_noirq(dev, pm_transition, true);
+ put_device(dev);
+ }
+
++static void device_resume_noirq(struct device *dev)
++{
++ if (dpm_async_fn(dev, async_resume_noirq))
++ return;
++
++ __device_resume_noirq(dev, pm_transition, false);
++}
++
+ static void dpm_noirq_resume_devices(pm_message_t state)
+ {
+ struct device *dev;
+@@ -699,14 +713,6 @@ static void dpm_noirq_resume_devices(pm_message_t state)
+ mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+
+- /*
+- * Advanced the async threads upfront,
+- * in case the starting of async threads is
+- * delayed by non-async resuming devices.
+- */
+- list_for_each_entry(dev, &dpm_noirq_list, power.entry)
+- dpm_async_fn(dev, async_resume_noirq);
+-
+ while (!list_empty(&dpm_noirq_list)) {
+ dev = to_device(dpm_noirq_list.next);
+ get_device(dev);
+@@ -714,17 +720,7 @@ static void dpm_noirq_resume_devices(pm_message_t state)
+
+ mutex_unlock(&dpm_list_mtx);
+
+- if (!is_async(dev)) {
+- int error;
+-
+- error = device_resume_noirq(dev, state, false);
+- if (error) {
+- suspend_stats.failed_resume_noirq++;
+- dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
+- dpm_save_failed_dev(dev_name(dev));
+- pm_dev_err(dev, state, " noirq", error);
+- }
+- }
++ device_resume_noirq(dev);
+
+ put_device(dev);
+
+@@ -754,14 +750,14 @@ void dpm_resume_noirq(pm_message_t state)
+ }
+
+ /**
+- * device_resume_early - Execute an "early resume" callback for given device.
++ * __device_resume_early - Execute an "early resume" callback for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
+ * @async: If true, the device is being resumed asynchronously.
+ *
+ * Runtime PM is disabled for @dev while this function is being executed.
+ */
+-static int device_resume_early(struct device *dev, pm_message_t state, bool async)
++static void __device_resume_early(struct device *dev, pm_message_t state, bool async)
+ {
+ pm_callback_t callback = NULL;
+ const char *info = NULL;
+@@ -814,21 +810,31 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
+
+ pm_runtime_enable(dev);
+ complete_all(&dev->power.completion);
+- return error;
++
++ if (error) {
++ suspend_stats.failed_resume_early++;
++ dpm_save_failed_step(SUSPEND_RESUME_EARLY);
++ dpm_save_failed_dev(dev_name(dev));
++ pm_dev_err(dev, state, async ? " async early" : " early", error);
++ }
+ }
+
+ static void async_resume_early(void *data, async_cookie_t cookie)
+ {
+ struct device *dev = data;
+- int error;
+-
+- error = device_resume_early(dev, pm_transition, true);
+- if (error)
+- pm_dev_err(dev, pm_transition, " async", error);
+
++ __device_resume_early(dev, pm_transition, true);
+ put_device(dev);
+ }
+
++static void device_resume_early(struct device *dev)
++{
++ if (dpm_async_fn(dev, async_resume_early))
++ return;
++
++ __device_resume_early(dev, pm_transition, false);
++}
++
+ /**
+ * dpm_resume_early - Execute "early resume" callbacks for all devices.
+ * @state: PM transition of the system being carried out.
+@@ -842,14 +848,6 @@ void dpm_resume_early(pm_message_t state)
+ mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+
+- /*
+- * Advanced the async threads upfront,
+- * in case the starting of async threads is
+- * delayed by non-async resuming devices.
+- */
+- list_for_each_entry(dev, &dpm_late_early_list, power.entry)
+- dpm_async_fn(dev, async_resume_early);
+-
+ while (!list_empty(&dpm_late_early_list)) {
+ dev = to_device(dpm_late_early_list.next);
+ get_device(dev);
+@@ -857,17 +855,7 @@ void dpm_resume_early(pm_message_t state)
+
+ mutex_unlock(&dpm_list_mtx);
+
+- if (!is_async(dev)) {
+- int error;
+-
+- error = device_resume_early(dev, state, false);
+- if (error) {
+- suspend_stats.failed_resume_early++;
+- dpm_save_failed_step(SUSPEND_RESUME_EARLY);
+- dpm_save_failed_dev(dev_name(dev));
+- pm_dev_err(dev, state, " early", error);
+- }
+- }
++ device_resume_early(dev);
+
+ put_device(dev);
+
+@@ -891,12 +879,12 @@ void dpm_resume_start(pm_message_t state)
+ EXPORT_SYMBOL_GPL(dpm_resume_start);
+
+ /**
+- * device_resume - Execute "resume" callbacks for given device.
++ * __device_resume - Execute "resume" callbacks for given device.
+ * @dev: Device to handle.
+ * @state: PM transition of the system being carried out.
+ * @async: If true, the device is being resumed asynchronously.
+ */
+-static int device_resume(struct device *dev, pm_message_t state, bool async)
++static void __device_resume(struct device *dev, pm_message_t state, bool async)
+ {
+ pm_callback_t callback = NULL;
+ const char *info = NULL;
+@@ -978,20 +966,30 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
+
+ TRACE_RESUME(error);
+
+- return error;
++ if (error) {
++ suspend_stats.failed_resume++;
++ dpm_save_failed_step(SUSPEND_RESUME);
++ dpm_save_failed_dev(dev_name(dev));
++ pm_dev_err(dev, state, async ? " async" : "", error);
++ }
+ }
+
+ static void async_resume(void *data, async_cookie_t cookie)
+ {
+ struct device *dev = data;
+- int error;
+
+- error = device_resume(dev, pm_transition, true);
+- if (error)
+- pm_dev_err(dev, pm_transition, " async", error);
++ __device_resume(dev, pm_transition, true);
+ put_device(dev);
+ }
+
++static void device_resume(struct device *dev)
++{
++ if (dpm_async_fn(dev, async_resume))
++ return;
++
++ __device_resume(dev, pm_transition, false);
++}
++
+ /**
+ * dpm_resume - Execute "resume" callbacks for non-sysdev devices.
+ * @state: PM transition of the system being carried out.
+@@ -1011,27 +1009,17 @@ void dpm_resume(pm_message_t state)
+ pm_transition = state;
+ async_error = 0;
+
+- list_for_each_entry(dev, &dpm_suspended_list, power.entry)
+- dpm_async_fn(dev, async_resume);
+-
+ while (!list_empty(&dpm_suspended_list)) {
+ dev = to_device(dpm_suspended_list.next);
++
+ get_device(dev);
+- if (!is_async(dev)) {
+- int error;
+
+- mutex_unlock(&dpm_list_mtx);
++ mutex_unlock(&dpm_list_mtx);
++
++ device_resume(dev);
+
+- error = device_resume(dev, state, false);
+- if (error) {
+- suspend_stats.failed_resume++;
+- dpm_save_failed_step(SUSPEND_RESUME);
+- dpm_save_failed_dev(dev_name(dev));
+- pm_dev_err(dev, state, "", error);
+- }
++ mutex_lock(&dpm_list_mtx);
+
+- mutex_lock(&dpm_list_mtx);
+- }
+ if (!list_empty(&dev->power.entry))
+ list_move_tail(&dev->power.entry, &dpm_prepared_list);
+
+--
+2.43.0
+
drm-tidss-fix-atomic_flush-check.patch
drm-bridge-nxp-ptn3460-simplify-some-error-checking.patch
cifs-fix-off-by-one-in-smb2_query_info_init.patch
+pm-core-remove-unnecessary-void-conversions.patch
+pm-sleep-fix-possible-deadlocks-in-core-system-wide-.patch
+bus-mhi-host-rename-struct-mhi_tre-to-struct-mhi_rin.patch
+bus-mhi-host-add-alignment-check-for-event-ring-read.patch
+fs-pipe-move-check-to-pipe_has_watch_queue.patch
+pipe-wakeup-wr_wait-after-setting-max_usage.patch
+arm-dts-qcom-sdx55-fix-usb-wakeup-interrupt-types.patch
+arm-dts-samsung-exynos4210-i9100-unconditionally-ena.patch
+arm-dts-qcom-sdx55-fix-pdc-interrupt-cells.patch
+arm-dts-qcom-sdx55-fix-usb-dp-dm-hs-phy-interrupts.patch
+arm-dts-qcom-sdx55-fix-usb-ss-wakeup.patch
+media-mtk-jpeg-fix-use-after-free-bug-due-to-error-p.patch
+mm-use-__pfn_to_section-instead-of-open-coding-it.patch
+mm-sparsemem-fix-race-in-accessing-memory_section-us.patch
+pm-devfreq-export-devfreq_get_freq_range-symbol-with.patch
+pm-devfreq-add-cpu-based-scaling-support-to-passive-.patch
+pm-devfreq-passive-reduce-duplicate-code-when-passiv.patch
+pm-devfreq-rework-freq_table-to-be-local-to-devfreq-.patch
+pm-devfreq-fix-buffer-overflow-in-trans_stat_show.patch
+btrfs-add-definition-for-extent_tree_v2.patch
+btrfs-don-t-abort-filesystem-when-attempting-to-snap.patch
+nfsd-modernize-nfsd4_release_lockowner.patch
+nfsd-add-documenting-comment-for-nfsd4_release_locko.patch
+nfsd-fix-release_lockowner.patch
+ksmbd-fix-global-oob-in-ksmbd_nl_policy.patch
+cpufreq-intel_pstate-drop-redundant-intel_pstate_get.patch
+cpufreq-intel_pstate-refine-computation-of-p-state-f.patch