mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines
@ 2026-08-28  5:36 Alexey Klimov
  2026-08-28  5:36 ` [PATCH v2 1/2] soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node Alexey Klimov
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Alexey Klimov @ 2026-08-28  5:36 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Alim Akhtar, Peter Griffin
  Cc: Sam Protsenko, linux-samsung-soc, linux-arm-kernel, linux-kernel,
	stable, Sashiko

This was reported by Sashiko here:
https://sashiko.dev/#/patchset/20260513-exynos850-cpuhotplug-v4-0-54fec5f65362@linaro.org?part=3
and was mainly introduced by enabling cpu hotplug
support and cpuidle for gs101-based SoCs.

In this second version one patch was dropped to keep things consistent with
downstream implementation and due to lack of information. Other patches
deal with a few missing error paths issues here and there in
setup_cpuhp_and_cpuidle() and around. They were updated per discussions.

Tested on exynos850 e850-96 board with sequential series that implements
hotplug. I don't see any regressions but testing from others will be
appreciated.

Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
---
Changes in v2:
- destroy_cpuhp_and_cpuidle() is called only if
  (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp) == true
  (as suggested by Peter) (second patch in this series);
- in clean_cpuhp_states error path the cpuhp states variables are now
  reset to CPUHP_INVALID;
- re-implemented "soc: samsung: exynos-pmu: fix use-after-free of interrupt
  generator node" -- used __free(device_node) at declaration;
  (as suggested by Peter);
- drop "[PATCH 1/3] soc: samsung: exynos-pmu: use target cpu ID in hotplug
  callbacks". If we get some information about CPUx_INFORM registers usage
  then we may fix it later, but for now it was decided to keep it
  consistent with downstream implementation;
- Link to v1: https://lore.kernel.org/r/20260605-exynos-pmu-cpuhp-idle-fixes-v1-0-0cd05c81a82d@linaro.org

---
Alexey Klimov (2):
      soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node
      soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup

 drivers/soc/samsung/exynos-pmu.c | 70 ++++++++++++++++++++++++++++++++--------
 1 file changed, 57 insertions(+), 13 deletions(-)
---
base-commit: 3d83758432b5e6ed9507500a57efb0f3af41ee7d
change-id: 20260605-exynos-pmu-cpuhp-idle-fixes-32f5ed7c969f

Best regards,
-- 
Alexey Klimov <alexey.klimov@linaro.org>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/2] soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node
  2026-08-28  5:36 [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines Alexey Klimov
@ 2026-08-28  5:36 ` Alexey Klimov
  2026-08-28  5:36 ` [PATCH v2 2/2] soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup Alexey Klimov
  2026-09-07 10:10 ` (subset) [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines Krzysztof Kozlowski
  2 siblings, 0 replies; 5+ messages in thread
From: Alexey Klimov @ 2026-08-28  5:36 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Alim Akhtar, Peter Griffin
  Cc: Sam Protsenko, linux-samsung-soc, linux-arm-kernel, linux-kernel,
	stable, Sashiko

The setup_cpuhp_and_cpuidle() parses the device tree node for the
interrupt generation block via of_parse_phandle() and decrements its
reference count using of_node_put() immediately after fetching the resource
address. However, later the intr_gen_node pointer is passed into
of_syscon_register_regmap().

Fix this by declaring intr_gen_node with __free() and removing
of_node_put().

Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260513-exynos850-cpuhotplug-v4-0-54fec5f65362@linaro.org?part=3
Fixes: 78b72897a5c8 ("soc: samsung: exynos-pmu: Enable CPU Idle for gs101")
Cc: stable@vger.kernel.org
Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
---
 drivers/soc/samsung/exynos-pmu.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
index f5fcdde9750e..efccdd63e40e 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -409,13 +409,12 @@ static struct notifier_block exynos_cpupm_reboot_nb = {
 
 static int setup_cpuhp_and_cpuidle(struct device *dev)
 {
-	struct device_node *intr_gen_node;
+	struct device_node *intr_gen_node __free(device_node) =
+		of_parse_phandle(dev->of_node, "google,pmu-intr-gen-syscon", 0);
 	struct resource intrgen_res;
 	void __iomem *virt_addr;
 	int ret, cpu;
 
-	intr_gen_node = of_parse_phandle(dev->of_node,
-					 "google,pmu-intr-gen-syscon", 0);
 	if (!intr_gen_node) {
 		/*
 		 * To maintain support for older DTs that didn't specify syscon
@@ -431,8 +430,6 @@ static int setup_cpuhp_and_cpuidle(struct device *dev)
 	 * syscon provided regmap.
 	 */
 	ret = of_address_to_resource(intr_gen_node, 0, &intrgen_res);
-	of_node_put(intr_gen_node);
-
 	virt_addr = devm_ioremap(dev, intrgen_res.start,
 				 resource_size(&intrgen_res));
 	if (!virt_addr)

-- 
2.51.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 2/2] soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup
  2026-08-28  5:36 [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines Alexey Klimov
  2026-08-28  5:36 ` [PATCH v2 1/2] soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node Alexey Klimov
@ 2026-08-28  5:36 ` Alexey Klimov
  2026-09-07 10:09   ` Krzysztof Kozlowski
  2026-09-07 10:10 ` (subset) [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines Krzysztof Kozlowski
  2 siblings, 1 reply; 5+ messages in thread
From: Alexey Klimov @ 2026-08-28  5:36 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Alim Akhtar, Peter Griffin
  Cc: Sam Protsenko, linux-samsung-soc, linux-arm-kernel, linux-kernel,
	stable, Sashiko

The setup_cpuhp_and_cpuidle() initialisation sequence currently ignores
the return values of cpuhp_setup_state(), cpu_pm_register_notifier(), and
register_reboot_notifier(). If any of these registrations fail during
probe() routine, the driver returns 0, leaving the driver partially
configured.

Furthermore, if anything after setup_cpuhp_and_cpuidle() fails in probe()
routine, for instance devm_mfd_add_devices(), the probe() lacks an error
path and leaves notifiers and cpu hotplug states registered.

Introduce variables for the cpu hotplug state IDs in exynos_pmu_context
struct, that should be initialised to CPUHP_INVALID by default. Check all
return codes in setup_cpuhp_and_cpuidle(), and add an error path to remove
registered states on failure. Finally, add destroy_cpuhp_and_cpuidle()
helper to safely tear down notifiers and cpu hotplug states.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260513-exynos850-cpuhotplug-v4-0-54fec5f65362@linaro.org?part=3
Fixes: 78b72897a5c8 ("soc: samsung: exynos-pmu: Enable CPU Idle for gs101")
Cc: stable@vger.kernel.org
Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
---
 drivers/soc/samsung/exynos-pmu.c | 63 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 8 deletions(-)

diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
index efccdd63e40e..fce922d5ab92 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -38,6 +38,8 @@ struct exynos_pmu_context {
 	unsigned long *in_cpuhp;
 	bool sys_insuspend;
 	bool sys_inreboot;
+	int cpuhp_prepare_state;
+	int cpuhp_online_state;
 };
 
 void __iomem *pmu_base_addr;
@@ -407,6 +409,17 @@ static struct notifier_block exynos_cpupm_reboot_nb = {
 	.notifier_call = exynos_cpupm_reboot_notifier,
 };
 
+static void destroy_cpuhp_and_cpuidle(void)
+{
+	cpu_pm_unregister_notifier(&gs101_cpu_pm_notifier);
+	unregister_reboot_notifier(&exynos_cpupm_reboot_nb);
+
+	if (pmu_context->cpuhp_prepare_state != CPUHP_INVALID)
+		cpuhp_remove_state(pmu_context->cpuhp_prepare_state);
+	if (pmu_context->cpuhp_online_state != CPUHP_INVALID)
+		cpuhp_remove_state(pmu_context->cpuhp_online_state);
+}
+
 static int setup_cpuhp_and_cpuidle(struct device *dev)
 {
 	struct device_node *intr_gen_node __free(device_node) =
@@ -458,16 +471,46 @@ static int setup_cpuhp_and_cpuidle(struct device *dev)
 		gs101_cpuhp_pmu_online(cpu);
 
 	/* register CPU hotplug callbacks */
-	cpuhp_setup_state(CPUHP_BP_PREPARE_DYN,	"soc/exynos-pmu:prepare",
-			  gs101_cpuhp_pmu_online, NULL);
+	pmu_context->cpuhp_prepare_state = CPUHP_INVALID;
+	pmu_context->cpuhp_online_state = CPUHP_INVALID;
+
+	ret = cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare",
+				gs101_cpuhp_pmu_online, NULL);
+	if (ret < 0)
+		return ret;
+
+	pmu_context->cpuhp_prepare_state = ret;
+
+	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online",
+				NULL, gs101_cpuhp_pmu_offline);
+	if (ret < 0)
+		goto clean_cpuhp_states;
 
-	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online",
-			  NULL, gs101_cpuhp_pmu_offline);
+	pmu_context->cpuhp_online_state = ret;
 
 	/* register CPU PM notifiers for cpuidle */
-	cpu_pm_register_notifier(&gs101_cpu_pm_notifier);
-	register_reboot_notifier(&exynos_cpupm_reboot_nb);
-	return 0;
+	ret = cpu_pm_register_notifier(&gs101_cpu_pm_notifier);
+	if (ret)
+		goto clean_cpuhp_states;
+
+	ret = register_reboot_notifier(&exynos_cpupm_reboot_nb);
+	if (!ret)
+		/* Success */
+		return ret;
+
+	cpu_pm_unregister_notifier(&gs101_cpu_pm_notifier);
+
+clean_cpuhp_states:
+	if (pmu_context->cpuhp_prepare_state != CPUHP_INVALID) {
+		cpuhp_remove_state(pmu_context->cpuhp_prepare_state);
+		pmu_context->cpuhp_prepare_state = CPUHP_INVALID;
+	}
+	if (pmu_context->cpuhp_online_state != CPUHP_INVALID) {
+		cpuhp_remove_state(pmu_context->cpuhp_online_state);
+		pmu_context->cpuhp_online_state = CPUHP_INVALID;
+	}
+
+	return ret;
 }
 
 static int exynos_pmu_probe(struct platform_device *pdev)
@@ -541,8 +584,12 @@ static int exynos_pmu_probe(struct platform_device *pdev)
 
 	ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, exynos_pmu_devs,
 				   ARRAY_SIZE(exynos_pmu_devs), NULL, 0, NULL);
-	if (ret)
+	if (ret) {
+		if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp)
+			destroy_cpuhp_and_cpuidle();
+
 		return ret;
+	}
 
 	if (devm_of_platform_populate(dev))
 		dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n");

-- 
2.51.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 2/2] soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup
  2026-08-28  5:36 ` [PATCH v2 2/2] soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup Alexey Klimov
@ 2026-09-07 10:09   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 5+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-07 10:09 UTC (permalink / raw)
  To: Alexey Klimov, Alim Akhtar, Peter Griffin
  Cc: Sam Protsenko, linux-samsung-soc, linux-arm-kernel, linux-kernel,
	stable, Sashiko

On 28/08/2026 07:36, Alexey Klimov wrote:
>  void __iomem *pmu_base_addr;
> @@ -407,6 +409,17 @@ static struct notifier_block exynos_cpupm_reboot_nb = {
>  	.notifier_call = exynos_cpupm_reboot_notifier,
>  };
>  
> +static void destroy_cpuhp_and_cpuidle(void)
> +{
> +	cpu_pm_unregister_notifier(&gs101_cpu_pm_notifier);
> +	unregister_reboot_notifier(&exynos_cpupm_reboot_nb);
> +
> +	if (pmu_context->cpuhp_prepare_state != CPUHP_INVALID)
> +		cpuhp_remove_state(pmu_context->cpuhp_prepare_state);
> +	if (pmu_context->cpuhp_online_state != CPUHP_INVALID)
> +		cpuhp_remove_state(pmu_context->cpuhp_online_state);
> +}

cleanup follows the setup usually, so this function should be after
setup_cpuhp_and_cpuidle().

> +
>  static int setup_cpuhp_and_cpuidle(struct device *dev)
>  {
>  	struct device_node *intr_gen_node __free(device_node) =
> @@ -458,16 +471,46 @@ static int setup_cpuhp_and_cpuidle(struct device *dev)
>  		gs101_cpuhp_pmu_online(cpu);
>  
>  	/* register CPU hotplug callbacks */
> -	cpuhp_setup_state(CPUHP_BP_PREPARE_DYN,	"soc/exynos-pmu:prepare",
> -			  gs101_cpuhp_pmu_online, NULL);
> +	pmu_context->cpuhp_prepare_state = CPUHP_INVALID;
> +	pmu_context->cpuhp_online_state = CPUHP_INVALID;
> +
> +	ret = cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare",
> +				gs101_cpuhp_pmu_online, NULL);
> +	if (ret < 0)
> +		return ret;
> +
> +	pmu_context->cpuhp_prepare_state = ret;
> +
> +	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online",
> +				NULL, gs101_cpuhp_pmu_offline);
> +	if (ret < 0)
> +		goto clean_cpuhp_states;

You have only one state to clean here, no? Error paths must be specific
- clean only what's needed, not a catch-all with if-checks.

>  
> -	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online",
> -			  NULL, gs101_cpuhp_pmu_offline);
> +	pmu_context->cpuhp_online_state = ret;
>  
>  	/* register CPU PM notifiers for cpuidle */
> -	cpu_pm_register_notifier(&gs101_cpu_pm_notifier);
> -	register_reboot_notifier(&exynos_cpupm_reboot_nb);
> -	return 0;
> +	ret = cpu_pm_register_notifier(&gs101_cpu_pm_notifier);
> +	if (ret)
> +		goto clean_cpuhp_states;
> +
> +	ret = register_reboot_notifier(&exynos_cpupm_reboot_nb);
> +	if (!ret)
> +		/* Success */
> +		return ret;
> +
> +	cpu_pm_unregister_notifier(&gs101_cpu_pm_notifier);
> +
> +clean_cpuhp_states:
> +	if (pmu_context->cpuhp_prepare_state != CPUHP_INVALID) {
> +		cpuhp_remove_state(pmu_context->cpuhp_prepare_state);
> +		pmu_context->cpuhp_prepare_state = CPUHP_INVALID;
> +	}
> +	if (pmu_context->cpuhp_online_state != CPUHP_INVALID) {
> +		cpuhp_remove_state(pmu_context->cpuhp_online_state);
> +		pmu_context->cpuhp_online_state = CPUHP_INVALID;
> +	}
> +
> +	return ret;
>  }
>  
>  static int exynos_pmu_probe(struct platform_device *pdev)
> @@ -541,8 +584,12 @@ static int exynos_pmu_probe(struct platform_device *pdev)
>  
>  	ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, exynos_pmu_devs,
>  				   ARRAY_SIZE(exynos_pmu_devs), NULL, 0, NULL);
> -	if (ret)
> +	if (ret) {
> +		if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp)
> +			destroy_cpuhp_and_cpuidle();
> +
>  		return ret;
> +	}
>  
>  	if (devm_of_platform_populate(dev))
>  		dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n");
> 


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: (subset) [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines
  2026-08-28  5:36 [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines Alexey Klimov
  2026-08-28  5:36 ` [PATCH v2 1/2] soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node Alexey Klimov
  2026-08-28  5:36 ` [PATCH v2 2/2] soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup Alexey Klimov
@ 2026-09-07 10:10 ` Krzysztof Kozlowski
  2 siblings, 0 replies; 5+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-07 10:10 UTC (permalink / raw)
  To: Alim Akhtar, Peter Griffin, Alexey Klimov
  Cc: Sam Protsenko, linux-samsung-soc, linux-arm-kernel, linux-kernel,
	stable, Sashiko


On Fri, 28 Aug 2026 06:36:45 +0100, Alexey Klimov wrote:
> This was reported by Sashiko here:
> https://sashiko.dev/#/patchset/20260513-exynos850-cpuhotplug-v4-0-54fec5f65362@linaro.org?part=3
> and was mainly introduced by enabling cpu hotplug
> support and cpuidle for gs101-based SoCs.
> 
> In this second version one patch was dropped to keep things consistent with
> downstream implementation and due to lack of information. Other patches
> deal with a few missing error paths issues here and there in
> setup_cpuhp_and_cpuidle() and around. They were updated per discussions.
> 
> [...]

Applied, thanks!

[1/2] soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node
      https://git.kernel.org/krzk/linux/c/48f344b3e83211025763ca9bc1c5f3dc544b9613

Best regards,
-- 
Krzysztof Kozlowski <krzk@kernel.org>


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-07 10:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-28  5:36 [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines Alexey Klimov
2026-08-28  5:36 ` [PATCH v2 1/2] soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node Alexey Klimov
2026-08-28  5:36 ` [PATCH v2 2/2] soc: samsung: exynos-pmu: fix error paths in cpuhotplug/idle states setup Alexey Klimov
2026-09-07 10:09   ` Krzysztof Kozlowski
2026-09-07 10:10 ` (subset) [PATCH v2 0/2] Exynos PMU fixes for cpu hotplug and cpuidle routines Krzysztof Kozlowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®