Commit 5bec2487 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regulator-fix-v5.11-rc5' of...

Merge tag 'regulator-fix-v5.11-rc5' of git://git.kernel.org/pub/scm/linux/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
parents 377bf660 14a71d50
......@@ -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;
......@@ -1829,7 +1829,7 @@ 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;
......@@ -1837,15 +1837,18 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
} 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);
}
......@@ -1859,7 +1862,8 @@ 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;
}
}
......@@ -1867,15 +1871,32 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
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
......@@ -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 */
......
......@@ -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)
{
......@@ -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)
{
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment