lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20260109-clk-samsung-autoclk-updates-v1-2-2394dcf242a9@linaro.org>
Date: Fri, 09 Jan 2026 17:27:24 +0000
From: André Draszik <andre.draszik@...aro.org>
To: Krzysztof Kozlowski <krzk@...nel.org>, 
 Sylwester Nawrocki <s.nawrocki@...sung.com>, 
 Chanwoo Choi <cw00.choi@...sung.com>, Alim Akhtar <alim.akhtar@...sung.com>, 
 Michael Turquette <mturquette@...libre.com>, 
 Stephen Boyd <sboyd@...nel.org>
Cc: Peter Griffin <peter.griffin@...aro.org>, 
 Tudor Ambarus <tudor.ambarus@...aro.org>, 
 Will McVicker <willmcvicker@...gle.com>, Juan Yescas <jyescas@...gle.com>, 
 linux-samsung-soc@...r.kernel.org, linux-clk@...r.kernel.org, 
 linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org, 
 André Draszik <andre.draszik@...aro.org>
Subject: [PATCH 2/3] clk: samsung: fix sysreg save/restore when PM is
 enabled for CMU

Currently, sysreg registers of a CMU that has PM and automatic clock
gating enabled are not saved / restored during runtime PM (RPM) or
s2idle. During normal suspend, they are accessed too late, after the
CMU (and potentially power domain) have been shut down, causing an
SError.

The reason is that these registers are registered to be saved/restored
via a syscore suspend handler which doesn't run during RPM or s2idle.
During normal suspend, this handler runs after the CMU has been shut
down. This registration happens as part of
samsung_clk_extended_sleep_init() via samsung_en_dyn_root_clk_gating().

When PM is enabled for a CMU, registers must be saved/restored via
exynos_arm64_cmu_suspend() / exynos_arm64_cmu_resume() respectively
instead. These use their own data structures and are unrelated to
anything that samsung_clk_extended_sleep_init() does. Calling it
unconditionally from samsung_en_dyn_root_clk_gating() therefore isn't
useful.

Update the code to prepare sysreg save / restore in a similar way to
how it handles other clock registers in the PM case already.
exynos_arm64_cmu_suspend() / exynos_arm64_cmu_resume() already handle
sysreg save/restore, just the setup was incorrect.

Fixes: 298fac4f4b96 ("clk: samsung: Implement automatic clock gating mode for CMUs")
Signed-off-by: André Draszik <andre.draszik@...aro.org>
---
 drivers/clk/samsung/clk-exynos-arm64.c | 32 ++++++++++++++++++++++++++------
 drivers/clk/samsung/clk.c              | 19 +++++++++++++------
 drivers/clk/samsung/clk.h              |  3 ++-
 3 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c
index 11e4d49f2390ba714eff5a329bb1f427cd6437b9..35d4de233cc1b4aa25490ff20d0f0372b8d3d0d6 100644
--- a/drivers/clk/samsung/clk-exynos-arm64.c
+++ b/drivers/clk/samsung/clk-exynos-arm64.c
@@ -174,7 +174,7 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
 		const struct samsung_cmu_info *cmu)
 {
 	struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
-	int i;
+	int i, ret;
 
 	data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs,
 						    cmu->nr_clk_regs);
@@ -182,8 +182,22 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
 		return -ENOMEM;
 
 	data->nr_clk_save = cmu->nr_clk_regs;
+
+	if (cmu->nr_sysreg_clk_regs) {
+		data->clk_sysreg_save =
+			samsung_clk_alloc_reg_dump(cmu->sysreg_clk_regs,
+						   cmu->nr_sysreg_clk_regs);
+		if (!data->clk_sysreg_save) {
+			ret = -ENOMEM;
+			goto free_clk_save;
+		}
+
+		data->nr_clk_sysreg = cmu->nr_sysreg_clk_regs;
+	}
+
 	data->clk_suspend = cmu->suspend_regs;
 	data->nr_clk_suspend = cmu->nr_suspend_regs;
+
 	data->nr_pclks = of_clk_get_parent_count(dev->of_node);
 	if (!data->nr_pclks)
 		return 0;
@@ -191,23 +205,29 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
 	data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks,
 				   GFP_KERNEL);
 	if (!data->pclks) {
-		kfree(data->clk_save);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto free_sysreg_save;
 	}
 
 	for (i = 0; i < data->nr_pclks; i++) {
 		struct clk *clk = of_clk_get(dev->of_node, i);
 
 		if (IS_ERR(clk)) {
-			kfree(data->clk_save);
 			while (--i >= 0)
 				clk_put(data->pclks[i]);
-			return PTR_ERR(clk);
+			ret = PTR_ERR(clk);
+			goto free_sysreg_save;
 		}
 		data->pclks[i] = clk;
 	}
 
 	return 0;
+
+free_sysreg_save:
+	kfree(data->clk_sysreg_save);
+free_clk_save:
+	kfree(data->clk_save);
+	return ret;
 }
 
 /**
@@ -305,7 +325,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
 	samsung_cmu_register_clocks(data->ctx, cmu, np);
 	samsung_clk_of_add_provider(dev->of_node, data->ctx);
 	/* sysreg DT nodes reference a clock in this CMU */
-	samsung_en_dyn_root_clk_gating(np, data->ctx, cmu);
+	samsung_en_dyn_root_clk_gating(np, data->ctx, cmu, true);
 	pm_runtime_put_sync(dev);
 
 	return 0;
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 417ec1786b5e77e17dda4022b417c1c6b79c59ab..9f68f079fd552f8dfb6898dbfb47dec0e84c626c 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -496,7 +496,8 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
 /* Enable Dynamic Root Clock Gating (DRCG) of bus components */
 void samsung_en_dyn_root_clk_gating(struct device_node *np,
 				    struct samsung_clk_provider *ctx,
-				    const struct samsung_cmu_info *cmu)
+				    const struct samsung_cmu_info *cmu,
+				    bool cmu_has_pm)
 {
 	if (!ctx->auto_clock_gate)
 		return;
@@ -513,10 +514,16 @@ void samsung_en_dyn_root_clk_gating(struct device_node *np,
 			regmap_write_bits(ctx->sysreg, ctx->memclk_offset,
 					  MEMCLK_EN, 0x0);
 
-		samsung_clk_extended_sleep_init(NULL, ctx->sysreg,
-						cmu->sysreg_clk_regs,
-						cmu->nr_sysreg_clk_regs,
-						NULL, 0);
+		if (!cmu_has_pm)
+			/*
+			 * When a CMU has PM support, clocks are saved/restored
+			 * via its PM handlers, so only register them with the
+			 * syscore suspend / resume paths if PM is not in use.
+			 */
+			samsung_clk_extended_sleep_init(NULL, ctx->sysreg,
+							cmu->sysreg_clk_regs,
+							cmu->nr_sysreg_clk_regs,
+							NULL, 0);
 	}
 }
 
@@ -548,7 +555,7 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
 	samsung_clk_of_add_provider(np, ctx);
 
 	/* sysreg DT nodes reference a clock in this CMU */
-	samsung_en_dyn_root_clk_gating(np, ctx, cmu);
+	samsung_en_dyn_root_clk_gating(np, ctx, cmu, false);
 
 	return ctx;
 }
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index a56aa3be54d817cd24bf2bc29427e783a1a9a859..b1192ca03db5035cc485771ff5597cf132234a2a 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -476,7 +476,8 @@ struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
 
 void samsung_en_dyn_root_clk_gating(struct device_node *np,
 				struct samsung_clk_provider *ctx,
-				const struct samsung_cmu_info *cmu);
+				const struct samsung_cmu_info *cmu,
+				bool cmu_has_pm);
 
 struct clk_hw *samsung_register_auto_gate(struct device *dev,
 		struct device_node *np, const char *name,

-- 
2.52.0.457.g6b5491de43-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ