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

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
Loading
Loading
Loading
Loading
+33 −11
Original line number Diff line number Diff line
@@ -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 */
+30 −0
Original line number Diff line number Diff line
@@ -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;