diff mbox series

[v5] regulator: core: Resolve supply name earlier to prevent double-init

Message ID 20220825212842.7176-1-christian@kohlschutter.com (mailing list archive)
State New, archived
Headers show
Series [v5] regulator: core: Resolve supply name earlier to prevent double-init | expand

Commit Message

Christian Kohlschütter Aug. 25, 2022, 9:28 p.m. UTC
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 | 58 ++++++++++++++++++++++++----------------
 1 file changed, 35 insertions(+), 23 deletions(-)

Comments

Christian Kohlschütter Aug. 25, 2022, 9:35 p.m. UTC | #1
This needed some further rearrangement. Please validate v5 of the patch.

Any branch that has the v4 patch should revert that change and freshly re-apply the v5 patch.
I hope this simplifies merging into mainline.

Verified by
1. rebooting numerous times (no mmc errors, partitions on mmc SD card are properly detected, no hangs upon reboot, i.e., the change appears to work)
2. "cat /sys/kernel/debug/regulator/regulator_summary" now correctly shows regulators, regulator-dummy use count is 1
3. ensuring that no entries for "(null)-SUPPLY' were found in dmesg or /sys

Thanks,
Christian
Marek Szyprowski Aug. 26, 2022, 5:55 a.m. UTC | #2
On 25.08.2022 23:28, 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.
>
> 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>

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---
>   drivers/regulator/core.c | 58 ++++++++++++++++++++++++----------------
>   1 file changed, 35 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> index 77f60eef960..2ff0ab2730f 100644
> --- a/drivers/regulator/core.c
> +++ b/drivers/regulator/core.c
> @@ -5391,6 +5391,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
>   	bool dangling_of_gpiod = false;
>   	struct device *dev;
>   	int ret, i;
> +	bool resolved_early = false;
>   
>   	if (cfg == NULL)
>   		return ERR_PTR(-EINVAL);
> @@ -5494,24 +5495,10 @@ 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 */
> -	if (init_data && init_data->regulator_init) {
> -		ret = init_data->regulator_init(rdev->reg_data);
> -		if (ret < 0)
> -			goto clean;
> -	}
> -
> -	if (config->ena_gpiod) {
> -		ret = regulator_ena_gpio_request(rdev, config);
> -		if (ret != 0) {
> -			rdev_err(rdev, "Failed to request enable GPIO: %pe\n",
> -				 ERR_PTR(ret));
> -			goto clean;
> -		}
> -		/* The regulator core took over the GPIO descriptor */
> -		dangling_cfg_gpiod = false;
> -		dangling_of_gpiod = false;
> -	}
> +	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;
>   
>   	/* register with sysfs */
>   	rdev->dev.class = &regulator_class;
> @@ -5533,13 +5520,38 @@ regulator_register(const struct regulator_desc *regulator_desc,
>   		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;
> +	if ((rdev->supply_name && !rdev->supply) &&
> +		(rdev->constraints->always_on ||
> +		 rdev->constraints->boot_on)) {
> +		ret = regulator_resolve_supply(rdev);
> +		if (ret != 0)
> +			rdev_dbg(rdev, "Unable to resolve supply early: %pe\n",
> +				 ERR_PTR(ret));
> +
> +		resolved_early = true;
> +	}
> +
> +	/* perform any regulator specific init */
> +	if (init_data && init_data->regulator_init) {
> +		ret = init_data->regulator_init(rdev->reg_data);
> +		if (ret < 0)
> +			goto wash;
> +	}
> +
> +	if (config->ena_gpiod) {
> +		ret = regulator_ena_gpio_request(rdev, config);
> +		if (ret != 0) {
> +			rdev_err(rdev, "Failed to request enable GPIO: %pe\n",
> +					 ERR_PTR(ret));
> +			goto wash;
> +		}
> +		/* The regulator core took over the GPIO descriptor */
> +		dangling_cfg_gpiod = false;
> +		dangling_of_gpiod = false;
> +	}
>   
>   	ret = set_machine_constraints(rdev);
> -	if (ret == -EPROBE_DEFER) {
> +	if (ret == -EPROBE_DEFER && !resolved_early) {
>   		/* Regulator might be in bypass mode and so needs its supply
>   		 * to set the constraints
>   		 */

Best regards
Mark Brown Aug. 29, 2022, 3:43 p.m. UTC | #3
On Thu, Aug 25, 2022 at 09:28:42PM +0000, 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.

Please do not submit new versions of already applied patches, please
submit incremental updates to the existing code.  Modifying existing
commits creates problems for other users building on top of those
commits so it's best practice to only change pubished git commits if
absolutely essential.

Please don't send new patches in reply to old patches or serieses, this
makes it harder for both people and tools to understand what is going
on - it can bury things in mailboxes and make it difficult to keep track
of what current patches are, both for the new patches and the old ones.
Christian Kohlschütter Aug. 29, 2022, 5:01 p.m. UTC | #4
> On 29. Aug 2022, at 17:43, Mark Brown <broonie@kernel.org> wrote:
> 
> On Thu, Aug 25, 2022 at 09:28:42PM +0000, 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.
> 
> Please do not submit new versions of already applied patches, please
> submit incremental updates to the existing code.  Modifying existing
> commits creates problems for other users building on top of those
> commits so it's best practice to only change pubished git commits if
> absolutely essential.
> 
> Please don't send new patches in reply to old patches or serieses, this
> makes it harder for both people and tools to understand what is going
> on - it can bury things in mailboxes and make it difficult to keep track
> of what current patches are, both for the new patches and the old ones.

My apologies, I wasn't aware that's not the preferred way forward.

Following up with "regulator: core: Fix regulator supply registration with sysfs", see
https://lore.kernel.org/all/20220829165543.24856-1-christian@kohlschutter.com/
Saravana Kannan Feb. 17, 2023, 11:22 p.m. UTC | #5
On Thu, Aug 25, 2022 at 2:28 PM Christian Kohlschütter
<christian@kohlschutter.com> 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.

In your case, can you elaborate which part of the constraints/init
twice caused the issue?

I'm trying to simplify some of the supply resolving code and I'm
trying to not break your use case.

-Saravana

>
> 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 | 58 ++++++++++++++++++++++++----------------
>  1 file changed, 35 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> index 77f60eef960..2ff0ab2730f 100644
> --- a/drivers/regulator/core.c
> +++ b/drivers/regulator/core.c
> @@ -5391,6 +5391,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
>         bool dangling_of_gpiod = false;
>         struct device *dev;
>         int ret, i;
> +       bool resolved_early = false;
>
>         if (cfg == NULL)
>                 return ERR_PTR(-EINVAL);
> @@ -5494,24 +5495,10 @@ 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 */
> -       if (init_data && init_data->regulator_init) {
> -               ret = init_data->regulator_init(rdev->reg_data);
> -               if (ret < 0)
> -                       goto clean;
> -       }
> -
> -       if (config->ena_gpiod) {
> -               ret = regulator_ena_gpio_request(rdev, config);
> -               if (ret != 0) {
> -                       rdev_err(rdev, "Failed to request enable GPIO: %pe\n",
> -                                ERR_PTR(ret));
> -                       goto clean;
> -               }
> -               /* The regulator core took over the GPIO descriptor */
> -               dangling_cfg_gpiod = false;
> -               dangling_of_gpiod = false;
> -       }
> +       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;
>
>         /* register with sysfs */
>         rdev->dev.class = &regulator_class;
> @@ -5533,13 +5520,38 @@ regulator_register(const struct regulator_desc *regulator_desc,
>                 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;
> +       if ((rdev->supply_name && !rdev->supply) &&
> +               (rdev->constraints->always_on ||
> +                rdev->constraints->boot_on)) {
> +               ret = regulator_resolve_supply(rdev);
> +               if (ret != 0)
> +                       rdev_dbg(rdev, "Unable to resolve supply early: %pe\n",
> +                                ERR_PTR(ret));
> +
> +               resolved_early = true;
> +       }
> +
> +       /* perform any regulator specific init */
> +       if (init_data && init_data->regulator_init) {
> +               ret = init_data->regulator_init(rdev->reg_data);
> +               if (ret < 0)
> +                       goto wash;
> +       }
> +
> +       if (config->ena_gpiod) {
> +               ret = regulator_ena_gpio_request(rdev, config);
> +               if (ret != 0) {
> +                       rdev_err(rdev, "Failed to request enable GPIO: %pe\n",
> +                                        ERR_PTR(ret));
> +                       goto wash;
> +               }
> +               /* The regulator core took over the GPIO descriptor */
> +               dangling_cfg_gpiod = false;
> +               dangling_of_gpiod = false;
> +       }
>
>         ret = set_machine_constraints(rdev);
> -       if (ret == -EPROBE_DEFER) {
> +       if (ret == -EPROBE_DEFER && !resolved_early) {
>                 /* Regulator might be in bypass mode and so needs its supply
>                  * to set the constraints
>                  */
> --
> 2.36.2
>
>
Christian Kohlschütter Feb. 17, 2023, 11:33 p.m. UTC | #6
On 18. Feb 2023, at 00:22, Saravana Kannan <saravanak@google.com> wrote:
> 
> On Thu, Aug 25, 2022 at 2:28 PM Christian Kohlschütter
> <christian@kohlschutter.com> 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.
> 
> In your case, can you elaborate which part of the constraints/init
> twice caused the issue?
> 
> I'm trying to simplify some of the supply resolving code and I'm
> trying to not break your use case.
> 
> -Saravana

Here's a write-up of my use case, and how we got to the solution:
https://kohlschuetter.github.io/blog/posts/2022/10/28/linux-nanopi-r4s/
Saravana Kannan Feb. 17, 2023, 11:46 p.m. UTC | #7
On Fri, Feb 17, 2023 at 3:33 PM Christian Kohlschütter
<christian@kohlschutter.com> wrote:
>
> On 18. Feb 2023, at 00:22, Saravana Kannan <saravanak@google.com> wrote:
> >
> > On Thu, Aug 25, 2022 at 2:28 PM Christian Kohlschütter
> > <christian@kohlschutter.com> 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.
> >
> > In your case, can you elaborate which part of the constraints/init
> > twice caused the issue?
> >
> > I'm trying to simplify some of the supply resolving code and I'm
> > trying to not break your use case.
> >
> > -Saravana
>
> Here's a write-up of my use case, and how we got to the solution:
> https://kohlschuetter.github.io/blog/posts/2022/10/28/linux-nanopi-r4s/

I did read the write up before I sent my request. I'm asking for
specifics on which functions in the set_machine_constraints() was
causing the issue. And it's also a bit unclear to me if the issue was
with having stuff called twice on the alway-on regulator or the
supply.

-Saravana
Christian Kohlschütter Feb. 18, 2023, 12:01 a.m. UTC | #8
On 18. Feb 2023, at 00:46, Saravana Kannan <saravanak@google.com> wrote:
> 
> On Fri, Feb 17, 2023 at 3:33 PM Christian Kohlschütter
> <christian@kohlschutter.com> wrote:
>> 
>> On 18. Feb 2023, at 00:22, Saravana Kannan <saravanak@google.com> wrote:
>>> 
>>> On Thu, Aug 25, 2022 at 2:28 PM Christian Kohlschütter
>>> <christian@kohlschutter.com> 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.
>>> 
>>> In your case, can you elaborate which part of the constraints/init
>>> twice caused the issue?
>>> 
>>> I'm trying to simplify some of the supply resolving code and I'm
>>> trying to not break your use case.
>>> 
>>> -Saravana
>> 
>> Here's a write-up of my use case, and how we got to the solution:
>> https://kohlschuetter.github.io/blog/posts/2022/10/28/linux-nanopi-r4s/
> 
> I did read the write up before I sent my request. I'm asking for
> specifics on which functions in the set_machine_constraints() was
> causing the issue. And it's also a bit unclear to me if the issue was
> with having stuff called twice on the alway-on regulator or the
> supply.
> 
> -Saravana

I'm afraid I cannot give a more detailed answer than what's in the write up and the previous discussion on this mailing list; I thought it's pretty detailed already.

However, it should be relatively straightforward to reproduce the issue.
Saravana Kannan Feb. 18, 2023, 12:05 a.m. UTC | #9
On Fri, Feb 17, 2023 at 4:01 PM Christian Kohlschütter
<christian@kohlschutter.com> wrote:
>
> On 18. Feb 2023, at 00:46, Saravana Kannan <saravanak@google.com> wrote:
> >
> > On Fri, Feb 17, 2023 at 3:33 PM Christian Kohlschütter
> > <christian@kohlschutter.com> wrote:
> >>
> >> On 18. Feb 2023, at 00:22, Saravana Kannan <saravanak@google.com> wrote:
> >>>
> >>> On Thu, Aug 25, 2022 at 2:28 PM Christian Kohlschütter
> >>> <christian@kohlschutter.com> 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.
> >>>
> >>> In your case, can you elaborate which part of the constraints/init
> >>> twice caused the issue?
> >>>
> >>> I'm trying to simplify some of the supply resolving code and I'm
> >>> trying to not break your use case.
> >>>
> >>> -Saravana
> >>
> >> Here's a write-up of my use case, and how we got to the solution:
> >> https://kohlschuetter.github.io/blog/posts/2022/10/28/linux-nanopi-r4s/
> >
> > I did read the write up before I sent my request. I'm asking for
> > specifics on which functions in the set_machine_constraints() was
> > causing the issue. And it's also a bit unclear to me if the issue was
> > with having stuff called twice on the alway-on regulator or the
> > supply.
> >
> > -Saravana
>
> I'm afraid I cannot give a more detailed answer than what's in the write up and the previous discussion on this mailing list; I thought it's pretty detailed already.

Well, I do my best not to break your use case with whatever info you
are willing to provide. We'll figure it out one way or another I
suppose.

> However, it should be relatively straightforward to reproduce the issue.

If one has the hardware. Which I don't.

-Saravana
diff mbox series

Patch

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 77f60eef960..2ff0ab2730f 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -5391,6 +5391,7 @@  regulator_register(const struct regulator_desc *regulator_desc,
 	bool dangling_of_gpiod = false;
 	struct device *dev;
 	int ret, i;
+	bool resolved_early = false;
 
 	if (cfg == NULL)
 		return ERR_PTR(-EINVAL);
@@ -5494,24 +5495,10 @@  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 */
-	if (init_data && init_data->regulator_init) {
-		ret = init_data->regulator_init(rdev->reg_data);
-		if (ret < 0)
-			goto clean;
-	}
-
-	if (config->ena_gpiod) {
-		ret = regulator_ena_gpio_request(rdev, config);
-		if (ret != 0) {
-			rdev_err(rdev, "Failed to request enable GPIO: %pe\n",
-				 ERR_PTR(ret));
-			goto clean;
-		}
-		/* The regulator core took over the GPIO descriptor */
-		dangling_cfg_gpiod = false;
-		dangling_of_gpiod = false;
-	}
+	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;
 
 	/* register with sysfs */
 	rdev->dev.class = &regulator_class;
@@ -5533,13 +5520,38 @@  regulator_register(const struct regulator_desc *regulator_desc,
 		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;
+	if ((rdev->supply_name && !rdev->supply) &&
+		(rdev->constraints->always_on ||
+		 rdev->constraints->boot_on)) {
+		ret = regulator_resolve_supply(rdev);
+		if (ret != 0)
+			rdev_dbg(rdev, "Unable to resolve supply early: %pe\n",
+				 ERR_PTR(ret));
+
+		resolved_early = true;
+	}
+
+	/* perform any regulator specific init */
+	if (init_data && init_data->regulator_init) {
+		ret = init_data->regulator_init(rdev->reg_data);
+		if (ret < 0)
+			goto wash;
+	}
+
+	if (config->ena_gpiod) {
+		ret = regulator_ena_gpio_request(rdev, config);
+		if (ret != 0) {
+			rdev_err(rdev, "Failed to request enable GPIO: %pe\n",
+					 ERR_PTR(ret));
+			goto wash;
+		}
+		/* The regulator core took over the GPIO descriptor */
+		dangling_cfg_gpiod = false;
+		dangling_of_gpiod = false;
+	}
 
 	ret = set_machine_constraints(rdev);
-	if (ret == -EPROBE_DEFER) {
+	if (ret == -EPROBE_DEFER && !resolved_early) {
 		/* Regulator might be in bypass mode and so needs its supply
 		 * to set the constraints
 		 */