linux-rockchip.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] regulator: core: Resolve supply name earlier to prevent double-init
@ 2022-07-15 20:32 Christian Kohlschütter
  2022-07-15 20:51 ` Christian Kohlschütter
  2022-07-21 15:01 ` Mark Brown
  0 siblings, 2 replies; 6+ messages in thread
From: Christian Kohlschütter @ 2022-07-15 20:32 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, linux-kernel
  Cc: Robin Murphy, wens, Heiko Stübner, Markus Reichl,
	linux-arm-kernel, open list:ARM/Rockchip SoC...,
	Linux MMC List

Previously, an unresolved regulator supply reference upon calling
regulator_register on an always-on or boot-on regulator caused
set_machine_constraints to be called twice.

This in turn may initialize the regulator twice, leading to voltage
glitches that are timing-dependent. A simple, unrelated configuration
change may be enough to hide this problem, only to be surfaced by
chance.

One such example is the SD-Card voltage regulator in a NanoPI R4S that
would not initialize reliably unless the registration flow was just
complex enough to allow the regulator to properly reset between calls.

Fix this by re-arranging regulator_register, trying resolve the
regulator's supply early enough that set_machine_constraints does not
need to be called twice.

Signed-off-by: Christian Kohlschütter <christian@kohlschutter.com>
---
 drivers/regulator/core.c | 42 ++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c4d844ffad7a..728840827e9c 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -5433,7 +5433,34 @@ regulator_register(const struct regulator_desc *regulator_desc,
 	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
 	INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
 
-	/* preform any regulator specific init */
+	/* set regulator constraints */
+	if (init_data)
+		rdev->constraints = kmemdup(&init_data->constraints,
+					    sizeof(*rdev->constraints),
+					    GFP_KERNEL);
+	else
+		rdev->constraints = kzalloc(sizeof(*rdev->constraints),
+					    GFP_KERNEL);
+
+	if (init_data && init_data->supply_regulator)
+		rdev->supply_name = init_data->supply_regulator;
+	else if (regulator_desc->supply_name)
+		rdev->supply_name = regulator_desc->supply_name;
+
+	if ((rdev->supply_name && !rdev->supply) && rdev->constraints
+		&& (rdev->constraints->always_on || rdev->constraints->boot_on)) {
+		/* Try to resolve the name of the supplying regulator here first
+		 * so we prevent double-initializing the regulator, which may
+		 * cause timing-specific voltage brownouts/glitches that are
+		 * hard to debug.
+		 */
+		ret = regulator_resolve_supply(rdev);
+		if (ret)
+			rdev_dbg(rdev, "unable to resolve supply early: %pe\n",
+					 ERR_PTR(ret));
+	}
+
+	/* perform any regulator specific init */
 	if (init_data && init_data->regulator_init) {
 		ret = init_data->regulator_init(rdev->reg_data);
 		if (ret < 0)
@@ -5459,24 +5486,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
 		    (unsigned long) atomic_inc_return(&regulator_no));
 	dev_set_drvdata(&rdev->dev, rdev);
 
-	/* set regulator constraints */
-	if (init_data)
-		rdev->constraints = kmemdup(&init_data->constraints,
-					    sizeof(*rdev->constraints),
-					    GFP_KERNEL);
-	else
-		rdev->constraints = kzalloc(sizeof(*rdev->constraints),
-					    GFP_KERNEL);
 	if (!rdev->constraints) {
 		ret = -ENOMEM;
 		goto wash;
 	}
 
-	if (init_data && init_data->supply_regulator)
-		rdev->supply_name = init_data->supply_regulator;
-	else if (regulator_desc->supply_name)
-		rdev->supply_name = regulator_desc->supply_name;
-
 	ret = set_machine_constraints(rdev);
 	if (ret == -EPROBE_DEFER) {
 		/* Regulator might be in bypass mode and so needs its supply
-- 
2.36.1


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH] regulator: core: Resolve supply name earlier to prevent double-init
  2022-07-15 20:32 [PATCH] regulator: core: Resolve supply name earlier to prevent double-init Christian Kohlschütter
@ 2022-07-15 20:51 ` Christian Kohlschütter
  2022-07-21 15:01 ` Mark Brown
  1 sibling, 0 replies; 6+ messages in thread
From: Christian Kohlschütter @ 2022-07-15 20:51 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, linux-kernel
  Cc: Robin Murphy, wens, Heiko Stübner, Markus Reichl,
	linux-arm-kernel, open list:ARM/Rockchip SoC...,
	Linux MMC List

Hi all,

This is a follow-up patch from my patch on mmc side:
[PATCH v4] arm64: dts: rockchip: Fix SD card init on rk3399-nanopi4
https://patchwork.kernel.org/project/linux-rockchip/patch/73F9AED0-D2A8-4294-B6E1-1B92D2A36529@kohlschutter.com/

Thanks to Robin Murphy's help, we were able to figure out that my NanoPI R4S's SD-Card voltage regulator was initialized twice and that a voltage drop was the reason for the initialization failure.
Adding an mdelay to the init code, or — surprisingly — adding a "regulator-uv-protection-microvolt" declaration had "fixed" the issue in 99/100 tries.

Best,
Christian

from arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi:
vcc3v0_sd: vcc3v0-sd {
        compatible = "regulator-fixed";
        enable-active-high;
        gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
        pinctrl-names = "default";
        pinctrl-0 = <&sdmmc0_pwr_h>;
        regulator-always-on;
        regulator-min-microvolt = <3000000>;
        regulator-max-microvolt = <3000000>;
        regulator-name = "vcc3v0_sd";
        vin-supply = <&vcc3v3_sys>;
};                                        

> Am 15.07.2022 um 22:32 schrieb Christian Kohlschütter <christian@kohlschutter.com>:
> 
> Previously, an unresolved regulator supply reference upon calling
> regulator_register on an always-on or boot-on regulator caused
> set_machine_constraints to be called twice.
> 
> This in turn may initialize the regulator twice, leading to voltage
> glitches that are timing-dependent. A simple, unrelated configuration
> change may be enough to hide this problem, only to be surfaced by
> chance.
> 
> One such example is the SD-Card voltage regulator in a NanoPI R4S that
> would not initialize reliably unless the registration flow was just
> complex enough to allow the regulator to properly reset between calls.
> 
> Fix this by re-arranging regulator_register, trying resolve the
> regulator's supply early enough that set_machine_constraints does not
> need to be called twice.
> 
> Signed-off-by: Christian Kohlschütter <christian@kohlschutter.com>
> ---
> drivers/regulator/core.c | 42 ++++++++++++++++++++++++++--------------
> 1 file changed, 28 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> index c4d844ffad7a..728840827e9c 100644
> --- a/drivers/regulator/core.c
> +++ b/drivers/regulator/core.c
> @@ -5433,7 +5433,34 @@ regulator_register(const struct regulator_desc *regulator_desc,
> 	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
> 	INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
> 
> -	/* preform any regulator specific init */
> +	/* set regulator constraints */
> +	if (init_data)
> +		rdev->constraints = kmemdup(&init_data->constraints,
> +					    sizeof(*rdev->constraints),
> +					    GFP_KERNEL);
> +	else
> +		rdev->constraints = kzalloc(sizeof(*rdev->constraints),
> +					    GFP_KERNEL);
> +
> +	if (init_data && init_data->supply_regulator)
> +		rdev->supply_name = init_data->supply_regulator;
> +	else if (regulator_desc->supply_name)
> +		rdev->supply_name = regulator_desc->supply_name;
> +
> +	if ((rdev->supply_name && !rdev->supply) && rdev->constraints
> +		&& (rdev->constraints->always_on || rdev->constraints->boot_on)) {
> +		/* Try to resolve the name of the supplying regulator here first
> +		 * so we prevent double-initializing the regulator, which may
> +		 * cause timing-specific voltage brownouts/glitches that are
> +		 * hard to debug.
> +		 */
> +		ret = regulator_resolve_supply(rdev);
> +		if (ret)
> +			rdev_dbg(rdev, "unable to resolve supply early: %pe\n",
> +					 ERR_PTR(ret));
> +	}
> +
> +	/* perform any regulator specific init */
> 	if (init_data && init_data->regulator_init) {
> 		ret = init_data->regulator_init(rdev->reg_data);
> 		if (ret < 0)
> @@ -5459,24 +5486,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
> 		    (unsigned long) atomic_inc_return(&regulator_no));
> 	dev_set_drvdata(&rdev->dev, rdev);
> 
> -	/* set regulator constraints */
> -	if (init_data)
> -		rdev->constraints = kmemdup(&init_data->constraints,
> -					    sizeof(*rdev->constraints),
> -					    GFP_KERNEL);
> -	else
> -		rdev->constraints = kzalloc(sizeof(*rdev->constraints),
> -					    GFP_KERNEL);
> 	if (!rdev->constraints) {
> 		ret = -ENOMEM;
> 		goto wash;
> 	}
> 
> -	if (init_data && init_data->supply_regulator)
> -		rdev->supply_name = init_data->supply_regulator;
> -	else if (regulator_desc->supply_name)
> -		rdev->supply_name = regulator_desc->supply_name;
> -
> 	ret = set_machine_constraints(rdev);
> 	if (ret == -EPROBE_DEFER) {
> 		/* Regulator might be in bypass mode and so needs its supply
> -- 
> 2.36.1
> 


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH] regulator: core: Resolve supply name earlier to prevent double-init
  2022-07-15 20:32 [PATCH] regulator: core: Resolve supply name earlier to prevent double-init Christian Kohlschütter
  2022-07-15 20:51 ` Christian Kohlschütter
@ 2022-07-21 15:01 ` Mark Brown
  2022-07-22 17:42   ` [PATCH v2] " Christian Kohlschütter
  1 sibling, 1 reply; 6+ messages in thread
From: Mark Brown @ 2022-07-21 15:01 UTC (permalink / raw)
  To: Christian Kohlschütter
  Cc: Liam Girdwood, linux-kernel, Robin Murphy, wens,
	Heiko Stübner, Markus Reichl, linux-arm-kernel,
	open list:ARM/Rockchip SoC...,
	Linux MMC List


[-- Attachment #1.1: Type: text/plain, Size: 990 bytes --]

On Fri, Jul 15, 2022 at 10:32:16PM +0200, Christian Kohlschütter wrote:
> Previously, an unresolved regulator supply reference upon calling
> regulator_register on an always-on or boot-on regulator caused
> set_machine_constraints to be called twice.

One small thing below but otherwise I think this should be fine, however
since we're very near the merge window I'd rather hold off any apply at
-rc1, just to give more time for things to get tested.

> -	/* set regulator constraints */
> -	if (init_data)
> -		rdev->constraints = kmemdup(&init_data->constraints,
> -					    sizeof(*rdev->constraints),
> -					    GFP_KERNEL);
> -	else
> -		rdev->constraints = kzalloc(sizeof(*rdev->constraints),
> -					    GFP_KERNEL);
>  	if (!rdev->constraints) {
>  		ret = -ENOMEM;
>  		goto wash;
>  	}

The check for allocation failure should get pulled earlier in the
function along with the allocation, no sense in doing any of the other
work if we're going to fail.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 170 bytes --]

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* [PATCH v2] regulator: core: Resolve supply name earlier to prevent double-init
  2022-07-21 15:01 ` Mark Brown
@ 2022-07-22 17:42   ` Christian Kohlschütter
  2022-08-18 15:22     ` Mark Brown
  0 siblings, 1 reply; 6+ messages in thread
From: Christian Kohlschütter @ 2022-07-22 17:42 UTC (permalink / raw)
  To: Mark Brown
  Cc: Liam Girdwood, linux-kernel, Robin Murphy, wens,
	Heiko Stübner, Markus Reichl, linux-arm-kernel,
	open list:ARM/Rockchip SoC...,
	Linux MMC List

Previously, an unresolved regulator supply reference upon calling
regulator_register on an always-on or boot-on regulator caused
set_machine_constraints to be called twice.

This in turn may initialize the regulator twice, leading to voltage
glitches that are timing-dependent. A simple, unrelated configuration
change may be enough to hide this problem, only to be surfaced by
chance.

One such example is the SD-Card voltage regulator in a NanoPI R4S that
would not initialize reliably unless the registration flow was just
complex enough to allow the regulator to properly reset between calls.

Fix this by re-arranging regulator_register, trying resolve the
regulator's supply early enough that set_machine_constraints does not
need to be called twice.

Signed-off-by: Christian Kohlschütter <christian@kohlschutter.com>
---
 drivers/regulator/core.c | 51 +++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 19 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 398c8d6afd4..5c2b97ea633 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -5492,7 +5492,38 @@ regulator_register(const struct regulator_desc *regulator_desc,
 	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
 	INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
 
-	/* preform any regulator specific init */
+	/* set regulator constraints */
+	if (init_data)
+		rdev->constraints = kmemdup(&init_data->constraints,
+					    sizeof(*rdev->constraints),
+					    GFP_KERNEL);
+	else
+		rdev->constraints = kzalloc(sizeof(*rdev->constraints),
+					    GFP_KERNEL);
+	if (!rdev->constraints) {
+		ret = -ENOMEM;
+		goto clean;
+	}
+
+	if (init_data && init_data->supply_regulator)
+		rdev->supply_name = init_data->supply_regulator;
+	else if (regulator_desc->supply_name)
+		rdev->supply_name = regulator_desc->supply_name;
+
+	if ((rdev->supply_name && !rdev->supply) && rdev->constraints
+		&& (rdev->constraints->always_on || rdev->constraints->boot_on)) {
+		/* Try to resolve the name of the supplying regulator here first
+		 * so we prevent double-initializing the regulator, which may
+		 * cause timing-specific voltage brownouts/glitches that are
+		 * hard to debug.
+		 */
+		ret = regulator_resolve_supply(rdev);
+		if (ret)
+			rdev_dbg(rdev, "unable to resolve supply early: %pe\n",
+					 ERR_PTR(ret));
+	}
+
+	/* perform any regulator specific init */
 	if (init_data && init_data->regulator_init) {
 		ret = init_data->regulator_init(rdev->reg_data);
 		if (ret < 0)
@@ -5518,24 +5549,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
 		    (unsigned long) atomic_inc_return(&regulator_no));
 	dev_set_drvdata(&rdev->dev, rdev);
 
-	/* set regulator constraints */
-	if (init_data)
-		rdev->constraints = kmemdup(&init_data->constraints,
-					    sizeof(*rdev->constraints),
-					    GFP_KERNEL);
-	else
-		rdev->constraints = kzalloc(sizeof(*rdev->constraints),
-					    GFP_KERNEL);
-	if (!rdev->constraints) {
-		ret = -ENOMEM;
-		goto wash;
-	}
-
-	if (init_data && init_data->supply_regulator)
-		rdev->supply_name = init_data->supply_regulator;
-	else if (regulator_desc->supply_name)
-		rdev->supply_name = regulator_desc->supply_name;
-
 	ret = set_machine_constraints(rdev);
 	if (ret == -EPROBE_DEFER) {
 		/* Regulator might be in bypass mode and so needs its supply
-- 
2.36.2



_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH v2] regulator: core: Resolve supply name earlier to prevent double-init
  2022-07-22 17:42   ` [PATCH v2] " Christian Kohlschütter
@ 2022-08-18 15:22     ` Mark Brown
  2022-10-28 16:59       ` Christian Kohlschütter
  0 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2022-08-18 15:22 UTC (permalink / raw)
  To: Christian Kohlschütter
  Cc: wens, Heiko Stübner, open list:ARM/Rockchip SoC...,
	Linux MMC List, Markus Reichl, Liam Girdwood, linux-arm-kernel,
	Robin Murphy, linux-kernel

On Fri, 22 Jul 2022 19:42:27 +0200, Christian Kohlschütter wrote:
> Previously, an unresolved regulator supply reference upon calling
> regulator_register on an always-on or boot-on regulator caused
> set_machine_constraints to be called twice.
> 
> This in turn may initialize the regulator twice, leading to voltage
> glitches that are timing-dependent. A simple, unrelated configuration
> change may be enough to hide this problem, only to be surfaced by
> chance.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next

Thanks!

[1/1] regulator: core: Resolve supply name earlier to prevent double-init
      commit: 8a866d527ac0441c0eb14a991fa11358b476b11d

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

* Re: [PATCH v2] regulator: core: Resolve supply name earlier to prevent double-init
  2022-08-18 15:22     ` Mark Brown
@ 2022-10-28 16:59       ` Christian Kohlschütter
  0 siblings, 0 replies; 6+ messages in thread
From: Christian Kohlschütter @ 2022-10-28 16:59 UTC (permalink / raw)
  To: Mark Brown, Robin Murphy
  Cc: wens, Heiko Stübner, open list:ARM/Rockchip SoC...,
	Linux MMC List, Markus Reichl, Liam Girdwood, linux-arm-kernel,
	linux-kernel

> On 18. Aug 2022, at 17:22, Mark Brown <broonie@kernel.org> wrote:
> 
> On Fri, 22 Jul 2022 19:42:27 +0200, Christian Kohlschütter wrote:
>> Previously, an unresolved regulator supply reference upon calling
>> regulator_register on an always-on or boot-on regulator caused
>> set_machine_constraints to be called twice.
>> 
>> This in turn may initialize the regulator twice, leading to voltage
>> glitches that are timing-dependent. A simple, unrelated configuration
>> change may be enough to hide this problem, only to be surfaced by
>> chance.
>> 
>> [...]
> 
> Applied to
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next
> 
> Thanks!
> 
> [1/1] regulator: core: Resolve supply name earlier to prevent double-init
>    commit: 8a866d527ac0441c0eb14a991fa11358b476b11d
> 
> All being well this means that it will be integrated into the linux-next
> tree (usually sometime in the next 24 hours) and sent to Linus during
> the next merge window (or sooner if it is a bug fix), however if
> problems are discovered then the patch may be dropped or reverted.
> 
> You may get further e-mails resulting from automated or manual testing
> and review of the tree, please engage with people reporting problems and
> send followup patches addressing any issues that are reported if needed.
> 
> If any updates are required or you are submitting further changes they
> should be sent as incremental updates against current git, existing
> patches will not be replaced.
> 
> Please add any relevant lists and maintainers to the CCs when replying
> to this mail.
> 
> Thanks,
> Mark

I've finally managed to publish a blog post about this journey into regulator land; I hope you find it worthwhile.
https://kohlschuetter.github.io/blog/posts/2022/10/28/linux-nanopi-r4s/

Thanks to everybody involved for getting this far!
Special thanks go to Robin Murphy for pulling out the oscillator, and Mark Brown for helping that these changes get into 6.1.

Best,
Christian


_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

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

end of thread, other threads:[~2022-10-28 17:32 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-15 20:32 [PATCH] regulator: core: Resolve supply name earlier to prevent double-init Christian Kohlschütter
2022-07-15 20:51 ` Christian Kohlschütter
2022-07-21 15:01 ` Mark Brown
2022-07-22 17:42   ` [PATCH v2] " Christian Kohlschütter
2022-08-18 15:22     ` Mark Brown
2022-10-28 16:59       ` Christian Kohlschütter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).