Skip to content

Commit

Permalink
Merge tag 'regulator-fix-v5.11-rc5' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/broonie/regulator

Pull regulator fixes from Mark Brown:
 "The main thing here is a change to make sure that we don't try to
  double resolve the supply of a regulator if we have two probes going
  on simultaneously, plus an incremental fix on top of that to resolve a
  lockdep issue it introduced.

  There's also a patch from Dmitry Osipenko adding stubs for some
  functions to avoid build issues in consumers in some configurations"

* tag 'regulator-fix-v5.11-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator:
  regulator: Fix lockdep warning resolving supplies
  regulator: consumer: Add missing stubs to regulator/consumer.h
  regulator: core: avoid regulator_resolve_supply() race condition
  • Loading branch information
torvalds committed Jan 26, 2021
2 parents 377bf66 + 14a71d5 commit 5bec248
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 11 deletions.
44 changes: 33 additions & 11 deletions drivers/regulator/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1813,13 +1813,13 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
{
struct regulator_dev *r;
struct device *dev = rdev->dev.parent;
int ret;
int ret = 0;

/* No supply to resolve? */
if (!rdev->supply_name)
return 0;

/* Supply already resolved? */
/* Supply already resolved? (fast-path without locking contention) */
if (rdev->supply)
return 0;

Expand All @@ -1829,23 +1829,26 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)

/* Did the lookup explicitly defer for us? */
if (ret == -EPROBE_DEFER)
return ret;
goto out;

if (have_full_constraints()) {
r = dummy_regulator_rdev;
get_device(&r->dev);
} else {
dev_err(dev, "Failed to resolve %s-supply for %s\n",
rdev->supply_name, rdev->desc->name);
return -EPROBE_DEFER;
ret = -EPROBE_DEFER;
goto out;
}
}

if (r == rdev) {
dev_err(dev, "Supply for %s (%s) resolved to itself\n",
rdev->desc->name, rdev->supply_name);
if (!have_full_constraints())
return -EINVAL;
if (!have_full_constraints()) {
ret = -EINVAL;
goto out;
}
r = dummy_regulator_rdev;
get_device(&r->dev);
}
Expand All @@ -1859,23 +1862,41 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (r->dev.parent && r->dev.parent != rdev->dev.parent) {
if (!device_is_bound(r->dev.parent)) {
put_device(&r->dev);
return -EPROBE_DEFER;
ret = -EPROBE_DEFER;
goto out;
}
}

/* Recursively resolve the supply of the supply */
ret = regulator_resolve_supply(r);
if (ret < 0) {
put_device(&r->dev);
return ret;
goto out;
}

/*
* Recheck rdev->supply with rdev->mutex lock held to avoid a race
* between rdev->supply null check and setting rdev->supply in
* set_supply() from concurrent tasks.
*/
regulator_lock(rdev);

/* Supply just resolved by a concurrent task? */
if (rdev->supply) {
regulator_unlock(rdev);
put_device(&r->dev);
goto out;
}

ret = set_supply(rdev, r);
if (ret < 0) {
regulator_unlock(rdev);
put_device(&r->dev);
return ret;
goto out;
}

regulator_unlock(rdev);

/*
* In set_machine_constraints() we may have turned this regulator on
* but we couldn't propagate to the supply if it hadn't been resolved
Expand All @@ -1886,11 +1907,12 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (ret < 0) {
_regulator_put(rdev->supply);
rdev->supply = NULL;
return ret;
goto out;
}
}

return 0;
out:
return ret;
}

/* Internal regulator request function */
Expand Down
30 changes: 30 additions & 0 deletions include/linux/regulator/consumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,12 @@ regulator_get_exclusive(struct device *dev, const char *id)
return ERR_PTR(-ENODEV);
}

static inline struct regulator *__must_check
devm_regulator_get_exclusive(struct device *dev, const char *id)
{
return ERR_PTR(-ENODEV);
}

static inline struct regulator *__must_check
regulator_get_optional(struct device *dev, const char *id)
{
Expand Down Expand Up @@ -486,6 +492,11 @@ static inline int regulator_get_voltage(struct regulator *regulator)
return -EINVAL;
}

static inline int regulator_sync_voltage(struct regulator *regulator)
{
return -EINVAL;
}

static inline int regulator_is_supported_voltage(struct regulator *regulator,
int min_uV, int max_uV)
{
Expand Down Expand Up @@ -578,6 +589,25 @@ static inline int devm_regulator_unregister_notifier(struct regulator *regulator
return 0;
}

static inline int regulator_suspend_enable(struct regulator_dev *rdev,
suspend_state_t state)
{
return -EINVAL;
}

static inline int regulator_suspend_disable(struct regulator_dev *rdev,
suspend_state_t state)
{
return -EINVAL;
}

static inline int regulator_set_suspend_voltage(struct regulator *regulator,
int min_uV, int max_uV,
suspend_state_t state)
{
return -EINVAL;
}

static inline void *regulator_get_drvdata(struct regulator *regulator)
{
return NULL;
Expand Down

0 comments on commit 5bec248

Please sign in to comment.