Skip to content

Commit 5bec248

Browse files
committed
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
2 parents 377bf66 + 14a71d5 commit 5bec248

File tree

2 files changed

+63
-11
lines changed

2 files changed

+63
-11
lines changed

drivers/regulator/core.c

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,13 +1813,13 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
18131813
{
18141814
struct regulator_dev *r;
18151815
struct device *dev = rdev->dev.parent;
1816-
int ret;
1816+
int ret = 0;
18171817

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

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

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

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

18341834
if (have_full_constraints()) {
18351835
r = dummy_regulator_rdev;
18361836
get_device(&r->dev);
18371837
} else {
18381838
dev_err(dev, "Failed to resolve %s-supply for %s\n",
18391839
rdev->supply_name, rdev->desc->name);
1840-
return -EPROBE_DEFER;
1840+
ret = -EPROBE_DEFER;
1841+
goto out;
18411842
}
18421843
}
18431844

18441845
if (r == rdev) {
18451846
dev_err(dev, "Supply for %s (%s) resolved to itself\n",
18461847
rdev->desc->name, rdev->supply_name);
1847-
if (!have_full_constraints())
1848-
return -EINVAL;
1848+
if (!have_full_constraints()) {
1849+
ret = -EINVAL;
1850+
goto out;
1851+
}
18491852
r = dummy_regulator_rdev;
18501853
get_device(&r->dev);
18511854
}
@@ -1859,23 +1862,41 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
18591862
if (r->dev.parent && r->dev.parent != rdev->dev.parent) {
18601863
if (!device_is_bound(r->dev.parent)) {
18611864
put_device(&r->dev);
1862-
return -EPROBE_DEFER;
1865+
ret = -EPROBE_DEFER;
1866+
goto out;
18631867
}
18641868
}
18651869

18661870
/* Recursively resolve the supply of the supply */
18671871
ret = regulator_resolve_supply(r);
18681872
if (ret < 0) {
18691873
put_device(&r->dev);
1870-
return ret;
1874+
goto out;
1875+
}
1876+
1877+
/*
1878+
* Recheck rdev->supply with rdev->mutex lock held to avoid a race
1879+
* between rdev->supply null check and setting rdev->supply in
1880+
* set_supply() from concurrent tasks.
1881+
*/
1882+
regulator_lock(rdev);
1883+
1884+
/* Supply just resolved by a concurrent task? */
1885+
if (rdev->supply) {
1886+
regulator_unlock(rdev);
1887+
put_device(&r->dev);
1888+
goto out;
18711889
}
18721890

18731891
ret = set_supply(rdev, r);
18741892
if (ret < 0) {
1893+
regulator_unlock(rdev);
18751894
put_device(&r->dev);
1876-
return ret;
1895+
goto out;
18771896
}
18781897

1898+
regulator_unlock(rdev);
1899+
18791900
/*
18801901
* In set_machine_constraints() we may have turned this regulator on
18811902
* 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)
18861907
if (ret < 0) {
18871908
_regulator_put(rdev->supply);
18881909
rdev->supply = NULL;
1889-
return ret;
1910+
goto out;
18901911
}
18911912
}
18921913

1893-
return 0;
1914+
out:
1915+
return ret;
18941916
}
18951917

18961918
/* Internal regulator request function */

include/linux/regulator/consumer.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,12 @@ regulator_get_exclusive(struct device *dev, const char *id)
331331
return ERR_PTR(-ENODEV);
332332
}
333333

334+
static inline struct regulator *__must_check
335+
devm_regulator_get_exclusive(struct device *dev, const char *id)
336+
{
337+
return ERR_PTR(-ENODEV);
338+
}
339+
334340
static inline struct regulator *__must_check
335341
regulator_get_optional(struct device *dev, const char *id)
336342
{
@@ -486,6 +492,11 @@ static inline int regulator_get_voltage(struct regulator *regulator)
486492
return -EINVAL;
487493
}
488494

495+
static inline int regulator_sync_voltage(struct regulator *regulator)
496+
{
497+
return -EINVAL;
498+
}
499+
489500
static inline int regulator_is_supported_voltage(struct regulator *regulator,
490501
int min_uV, int max_uV)
491502
{
@@ -578,6 +589,25 @@ static inline int devm_regulator_unregister_notifier(struct regulator *regulator
578589
return 0;
579590
}
580591

592+
static inline int regulator_suspend_enable(struct regulator_dev *rdev,
593+
suspend_state_t state)
594+
{
595+
return -EINVAL;
596+
}
597+
598+
static inline int regulator_suspend_disable(struct regulator_dev *rdev,
599+
suspend_state_t state)
600+
{
601+
return -EINVAL;
602+
}
603+
604+
static inline int regulator_set_suspend_voltage(struct regulator *regulator,
605+
int min_uV, int max_uV,
606+
suspend_state_t state)
607+
{
608+
return -EINVAL;
609+
}
610+
581611
static inline void *regulator_get_drvdata(struct regulator *regulator)
582612
{
583613
return NULL;

0 commit comments

Comments
 (0)