linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 00/11] Continuing the work on coupled regulators
@ 2018-10-05 15:36 Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 01/11] regulator: core: Add voltage balancing mechanism Dmitry Osipenko
                   ` (11 more replies)
  0 siblings, 12 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Hello,

Maciej moved on to work on something else and kindly allowed me to
take over the coupled regulators patches [0] which I'll try to finalize.

I recently started to work on adding DVFS support to the CPUFreq driver
of NVIDIA Tegra20/30 which require the coupled regulators functionality.
Both Tegra20 and Tegra30 have the voltage "max-spread" constraint.
Tegra30 has an additional constraint, the "max-step" voltage.

What is done in this series:

1. Re-worked the original "Add voltage balancing mechanism" patch from
   Maciej by:
        1) Fixing infinite loop within regulator_balance_voltage().
        2) Handling suspend_state_t properly.
        3) Fixing broken compilation of the patch.

2. Added pair of patches to clean up regulator-couple resolving.

3. Changed device tree binding of the regulator-coupled-max-spread property
   to make it more flexible.

4. Added new device tree property, the regulator-max-step-microvolt.

5. Implemented wait/wound mutex which was suggested by Lucas Stach in the
   review comment to [0]. I've tested w/w locking extensively (including
   CONFIG_DEBUG_WW_MUTEX_SLOWPATH) and quite confident that everything is
   okay.

6. Patches were tested with KASAN on Tegra20 / Tegra30, I tried to cover
   various cases and verified that voltage constraints not violated under
   different circumstances.

Please review, thanks.

[0] https://lkml.org/lkml/2018/4/23/619

Dmitry Osipenko (9):
  regulator: core: Mutually resolve regulators coupling
  regulator: core: Don't allow to get regulator until all couples
    resolved
  dt-bindings: regulator: Change regulator-coupled-max-spread property
  regulator: core: Limit regulators coupling to a single couple
  dt-bindings: regulator: Document new regulator-max-step-microvolt
    property
  regulator: core: Add new max_uV_step constraint
  regulator: core: Decouple regulators on regulator_unregister()
  regulator: core: Use ww_mutex for regulators locking
  regulator: core: Properly handle case where supply is the couple

Maciej Purski (2):
  regulator: core: Add voltage balancing mechanism
  regulator: core: Change voltage setting path

 .../bindings/regulator/regulator.txt          |   7 +-
 drivers/regulator/core.c                      | 821 +++++++++++++++---
 drivers/regulator/of_regulator.c              |   4 +
 include/linux/regulator/driver.h              |   5 +-
 include/linux/regulator/machine.h             |   3 +
 5 files changed, 713 insertions(+), 127 deletions(-)

-- 
2.19.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v1 01/11] regulator: core: Add voltage balancing mechanism
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 02/11] regulator: core: Change voltage setting path Dmitry Osipenko
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

From: Maciej Purski <m.purski@samsung.com>

On Odroid XU3/4 and other Exynos5422 based boards there is a case, that
different devices on the board are supplied by different regulators
with non-fixed voltages. If one of these devices temporarily requires
higher voltage, there might occur a situation that the spread between
two devices' voltages is so high, that there is a risk of changing
'high' and 'low' states on the interconnection between devices powered
by those regulators.

Introduce new function regulator_balance_voltage(), which
keeps max_spread constraint fulfilled between a group of coupled
regulators. It should be called if a regulator changes its
voltage or after disabling or enabling. Disabled regulators should
follow changes of the enabled ones, but their consumers' demands
shouldn't be taken into account while calculating voltage of other
coupled regulators.

Find voltages, which are closest to suiting all the consumers' demands,
while fulfilling max_spread constraint, keeping the following rules:
- if one regulator is about to rise its voltage, rise others
  voltages in order to keep the max_spread
- if a regulator, which has caused rising other regulators, is
  lowered, lower other regulators if possible
- if one regulator is about to lower its voltage, but it hasn't caused
  rising other regulators, change its voltage so that it doesn't break the
  max_spread

Change regulators' voltages step by step, keeping max_spread constraint
fulfilled all the time. Function regulator_get_optimal_voltage()
should find the best possible change for the regulator, which doesn't
break max_spread constraint. In function regulator_balance_voltage()
optimize number of steps by finding highest voltage difference on
each iteration.

If a regulator, which is about to change its voltage, is not coupled,
method regulator_get_optimal_voltage() should simply return the lowest
voltage fulfilling consumers' demands.

Coupling should be checked only if the system is in PM_SUSPEND_ON state.

Signed-off-by: Maciej Purski <m.purski@samsung.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/regulator/core.c | 229 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 229 insertions(+)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 2c66b528aede..a2a513780fd7 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -105,6 +105,8 @@ static int _notifier_call_chain(struct regulator_dev *rdev,
 				  unsigned long event, void *data);
 static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 				     int min_uV, int max_uV);
+static int regulator_balance_voltage(struct regulator_dev *rdev,
+				     suspend_state_t state);
 static struct regulator *create_regulator(struct regulator_dev *rdev,
 					  struct device *dev,
 					  const char *supply_name);
@@ -3126,6 +3128,233 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 	return ret;
 }
 
+static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
+					 int *current_uV,
+					 int *min_uV, int *max_uV,
+					 suspend_state_t state,
+					 int n_coupled)
+{
+	struct coupling_desc *c_desc = &rdev->coupling_desc;
+	struct regulator_dev **c_rdevs = c_desc->coupled_rdevs;
+	struct regulation_constraints *constraints = rdev->constraints;
+	int max_spread = constraints->max_spread;
+	int desired_min_uV = 0, desired_max_uV = INT_MAX;
+	int max_current_uV = 0, min_current_uV = INT_MAX;
+	int highest_min_uV = 0, target_uV, possible_uV;
+	int i, ret;
+	bool done;
+
+	*current_uV = -1;
+
+	/*
+	 * If there are no coupled regulators, simply set the voltage
+	 * demanded by consumers.
+	 */
+	if (n_coupled == 1) {
+		/*
+		 * If consumers don't provide any demands, set voltage
+		 * to min_uV
+		 */
+		desired_min_uV = constraints->min_uV;
+		desired_max_uV = constraints->max_uV;
+
+		ret = regulator_check_consumers(rdev,
+						&desired_min_uV,
+						&desired_max_uV, state);
+		if (ret < 0)
+			return ret;
+
+		possible_uV = desired_min_uV;
+		done = true;
+
+		goto finish;
+	}
+
+	/* Find highest min desired voltage */
+	for (i = 0; i < n_coupled; i++) {
+		int tmp_min = 0;
+		int tmp_max = INT_MAX;
+
+		lockdep_assert_held_once(&c_rdevs[i]->mutex);
+
+		ret = regulator_check_consumers(c_rdevs[i],
+						&tmp_min,
+						&tmp_max, state);
+		if (ret < 0)
+			return ret;
+
+		ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max);
+		if (ret < 0)
+			return ret;
+
+		highest_min_uV = max(highest_min_uV, tmp_min);
+
+		if (i == 0) {
+			desired_min_uV = tmp_min;
+			desired_max_uV = tmp_max;
+		}
+	}
+
+	/*
+	 * Let target_uV be equal to the desired one if possible.
+	 * If not, set it to minimum voltage, allowed by other coupled
+	 * regulators.
+	 */
+	target_uV = max(desired_min_uV, highest_min_uV - max_spread);
+
+	/*
+	 * Find min and max voltages, which currently aren't violating
+	 * max_spread.
+	 */
+	for (i = 1; i < n_coupled; i++) {
+		int tmp_act;
+
+		if (!_regulator_is_enabled(c_rdevs[i]))
+			continue;
+
+		tmp_act = _regulator_get_voltage(c_rdevs[i]);
+		if (tmp_act < 0)
+			return tmp_act;
+
+		min_current_uV = min(tmp_act, min_current_uV);
+		max_current_uV = max(tmp_act, max_current_uV);
+	}
+
+	/* There aren't any other regulators enabled */
+	if (max_current_uV == 0) {
+		possible_uV = target_uV;
+	} else {
+		/*
+		 * Correct target voltage, so as it currently isn't
+		 * violating max_spread
+		 */
+		possible_uV = max(target_uV, max_current_uV - max_spread);
+		possible_uV = min(possible_uV, min_current_uV + max_spread);
+	}
+
+	if (possible_uV > desired_max_uV)
+		return -EINVAL;
+
+	done = (possible_uV == target_uV);
+	desired_min_uV = possible_uV;
+
+finish:
+	/* Set current_uV if wasn't done earlier in the code and if necessary */
+	if (n_coupled > 1 && *current_uV == -1) {
+
+		if (_regulator_is_enabled(rdev)) {
+			ret = _regulator_get_voltage(rdev);
+			if (ret < 0)
+				return ret;
+
+			*current_uV = ret;
+		} else {
+			*current_uV = desired_min_uV;
+		}
+	}
+
+	*min_uV = desired_min_uV;
+	*max_uV = desired_max_uV;
+
+	return done;
+}
+
+static int regulator_balance_voltage(struct regulator_dev *rdev,
+				     suspend_state_t state)
+{
+	struct regulator_dev **c_rdevs;
+	struct regulator_dev *best_rdev;
+	struct coupling_desc *c_desc = &rdev->coupling_desc;
+	int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev;
+	bool best_c_rdev_done, c_rdev_done[MAX_COUPLED];
+	unsigned int delta, best_delta;
+
+	c_rdevs = c_desc->coupled_rdevs;
+	n_coupled = c_desc->n_coupled;
+
+	/*
+	 * If system is in a state other than PM_SUSPEND_ON, don't check
+	 * other coupled regulators.
+	 */
+	if (state != PM_SUSPEND_ON)
+		n_coupled = 1;
+
+	if (c_desc->n_resolved < n_coupled) {
+		rdev_err(rdev, "Not all coupled regulators registered\n");
+		return -EPERM;
+	}
+
+	for (i = 0; i < n_coupled; i++)
+		c_rdev_done[i] = false;
+
+	/*
+	 * Find the best possible voltage change on each loop. Leave the loop
+	 * if there isn't any possible change.
+	 */
+	do {
+		best_c_rdev_done = false;
+		best_delta = 0;
+		best_min_uV = 0;
+		best_max_uV = 0;
+		best_c_rdev = 0;
+		best_rdev = NULL;
+
+		/*
+		 * Find highest difference between optimal voltage
+		 * and current voltage.
+		 */
+		for (i = 0; i < n_coupled; i++) {
+			/*
+			 * optimal_uV is the best voltage that can be set for
+			 * i-th regulator at the moment without violating
+			 * max_spread constraint in order to balance
+			 * the coupled voltages.
+			 */
+			int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0;
+
+			if (c_rdev_done[i])
+				continue;
+
+			ret = regulator_get_optimal_voltage(c_rdevs[i],
+							    &current_uV,
+							    &optimal_uV,
+							    &optimal_max_uV,
+							    state, n_coupled);
+			if (ret < 0)
+				goto out;
+
+			delta = abs(optimal_uV - current_uV);
+
+			if (delta && best_delta <= delta) {
+				best_c_rdev_done = ret;
+				best_delta = delta;
+				best_rdev = c_rdevs[i];
+				best_min_uV = optimal_uV;
+				best_max_uV = optimal_max_uV;
+				best_c_rdev = i;
+			}
+		}
+
+		/* Nothing to change, return successfully */
+		if (!best_rdev) {
+			ret = 0;
+			goto out;
+		}
+#if 0
+		ret = regulator_set_voltage_rdev(best_rdev, best_min_uV,
+						 best_max_uV, state);
+#endif
+		if (ret < 0)
+			goto out;
+
+		c_rdev_done[best_c_rdev] = best_c_rdev_done;
+
+	} while (n_coupled > 1);
+
+out:
+	return ret;
+}
+
 /**
  * regulator_set_voltage - set regulator output voltage
  * @regulator: regulator source
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 02/11] regulator: core: Change voltage setting path
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 01/11] regulator: core: Add voltage balancing mechanism Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 03/11] regulator: core: Mutually resolve regulators coupling Dmitry Osipenko
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

From: Maciej Purski <m.purski@samsung.com>

On Odroid XU3/4 and other Exynos5422 based boards there is a case, that
different devices on the board are supplied by different regulators
with non-fixed voltages. If one of these devices temporarily requires
higher voltage, there might occur a situation that the spread between
two devices' voltages is so high, that there is a risk of changing
'high' and 'low' states on the interconnection between devices powered
by those regulators.

Uncoupled regulators should be a special case of coupled regulators, so
they should share a common voltage setting path. When enabling,
disabling or setting voltage of a coupled regulator, all coupled
regulators should be locked. Regulator's supplies should be locked, when
setting voltage of a single regulator. Enabling a coupled regulator or
setting its voltage should not be possible if some of its coupled
regulators, has not been registered.

Add function for locking coupled regulators and supplies. Extract
a new function regulator_set_voltage_rdev() from
regulator_set_voltage_unlocked(), which is called when setting
voltage of a single regulator.

Signed-off-by: Maciej Purski <m.purski@samsung.com>
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/regulator/core.c | 145 ++++++++++++++++++++++++++-------------
 1 file changed, 99 insertions(+), 46 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index a2a513780fd7..5105eaaf3cef 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -107,6 +107,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 				     int min_uV, int max_uV);
 static int regulator_balance_voltage(struct regulator_dev *rdev,
 				     suspend_state_t state);
+static int regulator_set_voltage_rdev(struct regulator_dev *rdev,
+				      int min_uV, int max_uV,
+				      suspend_state_t state);
 static struct regulator *create_regulator(struct regulator_dev *rdev,
 					  struct device *dev,
 					  const char *supply_name);
@@ -198,37 +201,66 @@ static void regulator_unlock(struct regulator_dev *rdev)
 	}
 }
 
-/**
- * regulator_lock_supply - lock a regulator and its supplies
- * @rdev:         regulator source
- */
-static void regulator_lock_supply(struct regulator_dev *rdev)
+static int regulator_lock_recursive(struct regulator_dev *rdev,
+				    unsigned int subclass)
 {
+	struct regulator_dev *c_rdev;
 	int i;
 
-	for (i = 0; rdev; rdev = rdev_get_supply(rdev), i++)
-		regulator_lock_nested(rdev, i);
+	for (i = 0; i < rdev->coupling_desc.n_coupled; i++) {
+		c_rdev = rdev->coupling_desc.coupled_rdevs[i];
+
+		if (!c_rdev)
+			continue;
+
+		regulator_lock_nested(c_rdev, subclass++);
+
+		if (c_rdev->supply)
+			subclass =
+				regulator_lock_recursive(c_rdev->supply->rdev,
+							 subclass);
+	}
+
+	return subclass;
 }
 
 /**
- * regulator_unlock_supply - unlock a regulator and its supplies
- * @rdev:         regulator source
+ * regulator_unlock_dependent - unlock regulator's suppliers and coupled
+ *				regulators
+ * @rdev:			regulator source
+ *
+ * Unlock all regulators related with rdev by coupling or suppling.
  */
-static void regulator_unlock_supply(struct regulator_dev *rdev)
+static void regulator_unlock_dependent(struct regulator_dev *rdev)
 {
-	struct regulator *supply;
+	struct regulator_dev *c_rdev;
+	int i;
 
-	while (1) {
-		regulator_unlock(rdev);
-		supply = rdev->supply;
+	for (i = 0; i < rdev->coupling_desc.n_coupled; i++) {
+		c_rdev = rdev->coupling_desc.coupled_rdevs[i];
 
-		if (!rdev->supply)
-			return;
+		if (!c_rdev)
+			continue;
 
-		rdev = supply->rdev;
+		regulator_unlock(c_rdev);
+
+		if (c_rdev->supply)
+			regulator_unlock_dependent(c_rdev->supply->rdev);
 	}
 }
 
+/**
+ * regulator_lock_dependent - lock regulator's suppliers and coupled regulators
+ * @rdev:			regulator source
+ *
+ * This function as a wrapper on regulator_lock_recursive(), which locks
+ * all regulators related with rdev by coupling or suppling.
+ */
+static inline void regulator_lock_dependent(struct regulator_dev *rdev)
+{
+	regulator_lock_recursive(rdev, 0);
+}
+
 /**
  * of_get_regulator - get a regulator device node based on supply name
  * @dev: Device pointer for the consumer (of regulator) device
@@ -2289,9 +2321,16 @@ int regulator_enable(struct regulator *regulator)
 			return ret;
 	}
 
-	mutex_lock(&rdev->mutex);
+	regulator_lock_dependent(rdev);
+	/* balance only if there are regulators coupled */
+	if (rdev->coupling_desc.n_coupled > 1) {
+		ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+		if (ret != 0)
+			goto unlock;
+	}
 	ret = _regulator_enable(rdev);
-	mutex_unlock(&rdev->mutex);
+unlock:
+	regulator_unlock_dependent(rdev);
 
 	if (ret != 0 && rdev->supply)
 		regulator_disable(rdev->supply);
@@ -2397,9 +2436,11 @@ int regulator_disable(struct regulator *regulator)
 	if (regulator->always_on)
 		return 0;
 
-	mutex_lock(&rdev->mutex);
+	regulator_lock_dependent(rdev);
 	ret = _regulator_disable(rdev);
-	mutex_unlock(&rdev->mutex);
+	if (rdev->coupling_desc.n_coupled > 1)
+		regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+	regulator_unlock_dependent(rdev);
 
 	if (ret == 0 && rdev->supply)
 		regulator_disable(rdev->supply);
@@ -2448,10 +2489,12 @@ int regulator_force_disable(struct regulator *regulator)
 	struct regulator_dev *rdev = regulator->rdev;
 	int ret;
 
-	mutex_lock(&rdev->mutex);
+	regulator_lock_dependent(rdev);
 	regulator->uA_load = 0;
 	ret = _regulator_force_disable(regulator->rdev);
-	mutex_unlock(&rdev->mutex);
+	if (rdev->coupling_desc.n_coupled > 1)
+		regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+	regulator_unlock_dependent(rdev);
 
 	if (rdev->supply)
 		while (rdev->open_count--)
@@ -2599,9 +2642,9 @@ int regulator_is_enabled(struct regulator *regulator)
 	if (regulator->always_on)
 		return 1;
 
-	mutex_lock(&regulator->rdev->mutex);
+	regulator_lock_dependent(regulator->rdev);
 	ret = _regulator_is_enabled(regulator->rdev);
-	mutex_unlock(&regulator->rdev->mutex);
+	regulator_unlock_dependent(regulator->rdev);
 
 	return ret;
 }
@@ -3015,8 +3058,6 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 	int ret = 0;
 	int old_min_uV, old_max_uV;
 	int current_uV;
-	int best_supply_uV = 0;
-	int supply_change_uV = 0;
 
 	/* If we're setting the same range as last time the change
 	 * should be a noop (some cpufreq implementations use the same
@@ -3056,10 +3097,27 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 	voltage->min_uV = min_uV;
 	voltage->max_uV = max_uV;
 
-	ret = regulator_check_consumers(rdev, &min_uV, &max_uV, state);
+	/* for not coupled regulators this will just set the voltage */
+	ret = regulator_balance_voltage(rdev, state);
 	if (ret < 0)
 		goto out2;
 
+out:
+	return 0;
+out2:
+	voltage->min_uV = old_min_uV;
+	voltage->max_uV = old_max_uV;
+
+	return ret;
+}
+
+static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
+				      int max_uV, suspend_state_t state)
+{
+	int best_supply_uV = 0;
+	int supply_change_uV = 0;
+	int ret;
+
 	if (rdev->supply &&
 	    regulator_ops_is_valid(rdev->supply->rdev,
 				   REGULATOR_CHANGE_VOLTAGE) &&
@@ -3071,13 +3129,13 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 		selector = regulator_map_voltage(rdev, min_uV, max_uV);
 		if (selector < 0) {
 			ret = selector;
-			goto out2;
+			goto out;
 		}
 
 		best_supply_uV = _regulator_list_voltage(rdev, selector, 0);
 		if (best_supply_uV < 0) {
 			ret = best_supply_uV;
-			goto out2;
+			goto out;
 		}
 
 		best_supply_uV += rdev->desc->min_dropout_uV;
@@ -3085,7 +3143,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 		current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
 		if (current_supply_uV < 0) {
 			ret = current_supply_uV;
-			goto out2;
+			goto out;
 		}
 
 		supply_change_uV = best_supply_uV - current_supply_uV;
@@ -3097,7 +3155,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 		if (ret) {
 			dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
 					ret);
-			goto out2;
+			goto out;
 		}
 	}
 
@@ -3107,7 +3165,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 		ret = _regulator_do_set_suspend_voltage(rdev, min_uV,
 							max_uV, state);
 	if (ret < 0)
-		goto out2;
+		goto out;
 
 	if (supply_change_uV < 0) {
 		ret = regulator_set_voltage_unlocked(rdev->supply,
@@ -3120,11 +3178,6 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
 	}
 
 out:
-	return ret;
-out2:
-	voltage->min_uV = old_min_uV;
-	voltage->max_uV = old_max_uV;
-
 	return ret;
 }
 
@@ -3340,10 +3393,10 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
 			ret = 0;
 			goto out;
 		}
-#if 0
+
 		ret = regulator_set_voltage_rdev(best_rdev, best_min_uV,
 						 best_max_uV, state);
-#endif
+
 		if (ret < 0)
 			goto out;
 
@@ -3377,12 +3430,12 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
 {
 	int ret = 0;
 
-	regulator_lock_supply(regulator->rdev);
+	regulator_lock_dependent(regulator->rdev);
 
 	ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV,
 					     PM_SUSPEND_ON);
 
-	regulator_unlock_supply(regulator->rdev);
+	regulator_unlock_dependent(regulator->rdev);
 
 	return ret;
 }
@@ -3460,12 +3513,12 @@ int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV,
 	if (regulator_check_states(state) || state == PM_SUSPEND_ON)
 		return -EINVAL;
 
-	regulator_lock_supply(regulator->rdev);
+	regulator_lock_dependent(regulator->rdev);
 
 	ret = _regulator_set_suspend_voltage(regulator, min_uV,
 					     max_uV, state);
 
-	regulator_unlock_supply(regulator->rdev);
+	regulator_unlock_dependent(regulator->rdev);
 
 	return ret;
 }
@@ -3657,11 +3710,11 @@ int regulator_get_voltage(struct regulator *regulator)
 {
 	int ret;
 
-	regulator_lock_supply(regulator->rdev);
+	regulator_lock_dependent(regulator->rdev);
 
 	ret = _regulator_get_voltage(regulator->rdev);
 
-	regulator_unlock_supply(regulator->rdev);
+	regulator_unlock_dependent(regulator->rdev);
 
 	return ret;
 }
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 03/11] regulator: core: Mutually resolve regulators coupling
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 01/11] regulator: core: Add voltage balancing mechanism Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 02/11] regulator: core: Change voltage setting path Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 04/11] regulator: core: Don't allow to get regulator until all couples resolved Dmitry Osipenko
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

If registered regulator found a couple, then the couple can find the
registered regulator too and hence coupling can be mutually resolved
at the registration time.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/regulator/core.c | 54 +++++++++++++---------------------------
 1 file changed, 17 insertions(+), 37 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 5105eaaf3cef..925df9e6f1e3 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4439,7 +4439,7 @@ static int regulator_register_resolve_supply(struct device *dev, void *data)
 	return 0;
 }
 
-static int regulator_fill_coupling_array(struct regulator_dev *rdev)
+static void regulator_resolve_coupling(struct regulator_dev *rdev)
 {
 	struct coupling_desc *c_desc = &rdev->coupling_desc;
 	int n_coupled = c_desc->n_coupled;
@@ -4453,33 +4453,21 @@ static int regulator_fill_coupling_array(struct regulator_dev *rdev)
 
 		c_rdev = of_parse_coupled_regulator(rdev, i - 1);
 
-		if (c_rdev) {
-			c_desc->coupled_rdevs[i] = c_rdev;
-			c_desc->n_resolved++;
-		}
-	}
-
-	if (rdev->coupling_desc.n_resolved < n_coupled)
-		return -1;
-	else
-		return 0;
-}
+		if (!c_rdev)
+			continue;
 
-static int regulator_register_fill_coupling_array(struct device *dev,
-						  void *data)
-{
-	struct regulator_dev *rdev = dev_to_rdev(dev);
+		regulator_lock(c_rdev);
 
-	if (!IS_ENABLED(CONFIG_OF))
-		return 0;
+		c_desc->coupled_rdevs[i] = c_rdev;
+		c_desc->n_resolved++;
 
-	if (regulator_fill_coupling_array(rdev))
-		rdev_dbg(rdev, "unable to resolve coupling\n");
+		regulator_unlock(c_rdev);
 
-	return 0;
+		regulator_resolve_coupling(c_rdev);
+	}
 }
 
-static int regulator_resolve_coupling(struct regulator_dev *rdev)
+static int regulator_init_coupling(struct regulator_dev *rdev)
 {
 	int n_phandles;
 
@@ -4519,13 +4507,6 @@ static int regulator_resolve_coupling(struct regulator_dev *rdev)
 	if (!of_check_coupling_data(rdev))
 		return -EPERM;
 
-	/*
-	 * After everything has been checked, try to fill rdevs array
-	 * with pointers to regulators parsed from device tree. If some
-	 * regulators are not registered yet, retry in late init call
-	 */
-	regulator_fill_coupling_array(rdev);
-
 	return 0;
 }
 
@@ -4662,11 +4643,8 @@ regulator_register(const struct regulator_desc *regulator_desc,
 	if (ret < 0)
 		goto wash;
 
-	mutex_lock(&regulator_list_mutex);
-	ret = regulator_resolve_coupling(rdev);
-	mutex_unlock(&regulator_list_mutex);
-
-	if (ret != 0)
+	ret = regulator_init_coupling(rdev);
+	if (ret < 0)
 		goto wash;
 
 	/* add consumers devices */
@@ -4700,6 +4678,11 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
 	rdev_init_debugfs(rdev);
 
+	/* try to resolve regulators coupling since a new one was registered */
+	mutex_lock(&regulator_list_mutex);
+	regulator_resolve_coupling(rdev);
+	mutex_unlock(&regulator_list_mutex);
+
 	/* try to resolve regulators supply since a new one was registered */
 	class_for_each_device(&regulator_class, NULL, NULL,
 			      regulator_register_resolve_supply);
@@ -5155,9 +5138,6 @@ static int __init regulator_init_complete(void)
 	class_for_each_device(&regulator_class, NULL, NULL,
 			      regulator_late_cleanup);
 
-	class_for_each_device(&regulator_class, NULL, NULL,
-			      regulator_register_fill_coupling_array);
-
 	return 0;
 }
 late_initcall_sync(regulator_init_complete);
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 04/11] regulator: core: Don't allow to get regulator until all couples resolved
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (2 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 03/11] regulator: core: Mutually resolve regulators coupling Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property Dmitry Osipenko
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Don't allow to get regulator until all of its couples resolved because
consumer will get EPERM and coupling shall be transparent for the drivers.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/regulator/core.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 925df9e6f1e3..089e8ad8ef57 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1747,6 +1747,16 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
 		return regulator;
 	}
 
+	mutex_lock(&regulator_list_mutex);
+	ret = (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled);
+	mutex_unlock(&regulator_list_mutex);
+
+	if (ret != 0) {
+		regulator = ERR_PTR(-EPROBE_DEFER);
+		put_device(&rdev->dev);
+		return regulator;
+	}
+
 	ret = regulator_resolve_supply(rdev);
 	if (ret < 0) {
 		regulator = ERR_PTR(ret);
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (3 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 04/11] regulator: core: Don't allow to get regulator until all couples resolved Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-17 13:25   ` Rob Herring
  2018-10-17 13:27   ` Rob Herring
  2018-10-05 15:36 ` [PATCH v1 06/11] regulator: core: Limit regulators coupling to a single couple Dmitry Osipenko
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Redefine binding for regulator-coupled-max-spread property in a way that
max-spread values are defined per regulator couple instead of defining
single max-spread for the whole group of coupled regulators.

With that change the following regulators coupling configuration will be
possible:

regA: regulatorA {
	regulator-coupled-with = <&regB &regC>;
	regulator-coupled-max-spread = <100000 300000>;
};

regB: regulatorB {
	regulator-coupled-with = <&regA &regC>;
	regulator-coupled-max-spread = <100000 200000>;
};

regC: regulatorC {
	regulator-coupled-with = <&regA &regB>;
	regulator-coupled-max-spread = <300000 200000>;
};

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index a7cd36877bfe..9b525b657fca 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -76,8 +76,9 @@ Optional properties:
 - regulator-coupled-with: Regulators with which the regulator
   is coupled. The linkage is 2-way - all coupled regulators should be linked
   with each other. A regulator should not be coupled with its supplier.
-- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
-  in microvolts.
+- regulator-coupled-max-spread: Array of maximum spread between voltages of
+  coupled regulators in microvolts, each value in the array relates to the
+  corresponding couple specified by the regulator-coupled-with property.
 
 Deprecated properties:
 - regulator-compatible: If a regulator chip contains multiple
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 06/11] regulator: core: Limit regulators coupling to a single couple
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (4 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 07/11] dt-bindings: regulator: Document new regulator-max-step-microvolt property Dmitry Osipenko
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Device tree binding was changed in a way that now max-spread values must
be defied per regulator pair. Limit number of pairs in order to adapt to
the new binding without changing regulators code.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 include/linux/regulator/driver.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index a9c030192147..a05d37d0efa1 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -15,7 +15,7 @@
 #ifndef __LINUX_REGULATOR_DRIVER_H_
 #define __LINUX_REGULATOR_DRIVER_H_
 
-#define MAX_COUPLED		4
+#define MAX_COUPLED		2
 
 #include <linux/device.h>
 #include <linux/notifier.h>
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 07/11] dt-bindings: regulator: Document new regulator-max-step-microvolt property
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (5 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 06/11] regulator: core: Limit regulators coupling to a single couple Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-17 13:33   ` Rob Herring
  2018-10-05 15:36 ` [PATCH v1 08/11] regulator: core: Add new max_uV_step constraint Dmitry Osipenko
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Certain hardware may require supply voltage to be changed in steps. Define
new property that allow to describe such hardware.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 Documentation/devicetree/bindings/regulator/regulator.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 9b525b657fca..0c3a243c95df 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -79,6 +79,8 @@ Optional properties:
 - regulator-coupled-max-spread: Array of maximum spread between voltages of
   coupled regulators in microvolts, each value in the array relates to the
   corresponding couple specified by the regulator-coupled-with property.
+- regulator-max-step-microvolt: Maximum difference between current and target
+  voltages that can be changed safely in a single step.
 
 Deprecated properties:
 - regulator-compatible: If a regulator chip contains multiple
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 08/11] regulator: core: Add new max_uV_step constraint
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (6 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 07/11] dt-bindings: regulator: Document new regulator-max-step-microvolt property Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 09/11] regulator: core: Decouple regulators on regulator_unregister() Dmitry Osipenko
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

On NVIDIA Tegra30 there is a requirement for regulator "A" to have voltage
higher than voltage of regulator "B" by N microvolts, the N value changes
depending on the voltage of regulator "B". This is similar to min-spread
between voltages of regulators, the difference is that the spread value
isn't fixed. This means that extra carefulness is required for regulator
"A" to drop its voltage without violating the requirement, hence its
voltage should be changed in steps so that its couple "B" could follow
(there is also max-spread requirement).

Add new "max_uV_step" constraint that breaks voltage change into several
steps, each step is limited by the max_uV_step value.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/regulator/core.c          | 41 +++++++++++++++++++++++++++++++
 drivers/regulator/of_regulator.c  |  4 +++
 include/linux/regulator/machine.h |  3 +++
 3 files changed, 48 insertions(+)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 089e8ad8ef57..ba03bdf3716f 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3191,6 +3191,36 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
 	return ret;
 }
 
+static int regulator_limit_voltage_step(struct regulator_dev *rdev,
+					int *current_uV, int *min_uV)
+{
+	struct regulation_constraints *constraints = rdev->constraints;
+
+	/* Limit voltage change only if necessary */
+	if (!constraints->max_uV_step || !_regulator_is_enabled(rdev))
+		return 1;
+
+	if (*current_uV < 0) {
+		*current_uV = _regulator_get_voltage(rdev);
+
+		if (*current_uV < 0)
+			return *current_uV;
+	}
+
+	if (abs(*current_uV - *min_uV) <= constraints->max_uV_step)
+		return 1;
+
+	/* Clamp target voltage within the given step */
+	if (*current_uV < *min_uV)
+		*min_uV = min(*current_uV + constraints->max_uV_step,
+			      *min_uV);
+	else
+		*min_uV = max(*current_uV - constraints->max_uV_step,
+			      *min_uV);
+
+	return 0;
+}
+
 static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
 					 int *current_uV,
 					 int *min_uV, int *max_uV,
@@ -3302,6 +3332,17 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
 	desired_min_uV = possible_uV;
 
 finish:
+	/* Apply max_uV_step constraint if necessary */
+	if (state == PM_SUSPEND_ON) {
+		ret = regulator_limit_voltage_step(rdev, current_uV,
+						   &desired_min_uV);
+		if (ret < 0)
+			return ret;
+
+		if (ret == 0)
+			done = false;
+	}
+
 	/* Set current_uV if wasn't done earlier in the code and if necessary */
 	if (n_coupled > 1 && *current_uV == -1) {
 
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index c4223b3e0dff..a732f09d207b 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -170,6 +170,10 @@ static void of_get_regulation_constraints(struct device_node *np,
 				  &pval))
 		constraints->max_spread = pval;
 
+	if (!of_property_read_u32(np, "regulator-max-step-microvolt",
+				  &pval))
+		constraints->max_uV_step = pval;
+
 	constraints->over_current_protection = of_property_read_bool(np,
 					"regulator-over-current-protection");
 
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index a459a5e973a7..1d34a70ffda2 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -158,6 +158,9 @@ struct regulation_constraints {
 	/* used for coupled regulators */
 	int max_spread;
 
+	/* used for changing voltage in steps */
+	int max_uV_step;
+
 	/* valid regulator operating modes for this machine */
 	unsigned int valid_modes_mask;
 
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 09/11] regulator: core: Decouple regulators on regulator_unregister()
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (7 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 08/11] regulator: core: Add new max_uV_step constraint Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-05 15:36 ` [PATCH v1 10/11] regulator: core: Use ww_mutex for regulators locking Dmitry Osipenko
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Regulators shall be uncoupled if one of the couples disappear.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/regulator/core.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index ba03bdf3716f..783ec9c74104 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4518,6 +4518,43 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev)
 	}
 }
 
+static void regulator_remove_coupling(struct regulator_dev *rdev)
+{
+	struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc;
+	struct regulator_dev *__c_rdev, *c_rdev;
+	unsigned int __n_coupled, n_coupled;
+	int i, k;
+
+	n_coupled = c_desc->n_coupled;
+
+	for (i = 1; i < n_coupled; i++) {
+		c_rdev = c_desc->coupled_rdevs[i];
+
+		if (!c_rdev)
+			continue;
+
+		regulator_lock(c_rdev);
+
+		__c_desc = &c_rdev->coupling_desc;
+		__n_coupled = __c_desc->n_coupled;
+
+		for (k = 1; k < __n_coupled; k++) {
+			__c_rdev = __c_desc->coupled_rdevs[k];
+
+			if (__c_rdev == rdev) {
+				__c_desc->coupled_rdevs[k] = NULL;
+				__c_desc->n_resolved--;
+				break;
+			}
+		}
+
+		regulator_unlock(c_rdev);
+
+		c_desc->coupled_rdevs[i] = NULL;
+		c_desc->n_resolved--;
+	}
+}
+
 static int regulator_init_coupling(struct regulator_dev *rdev)
 {
 	int n_phandles;
@@ -4776,6 +4813,7 @@ void regulator_unregister(struct regulator_dev *rdev)
 	debugfs_remove_recursive(rdev->debugfs);
 	flush_work(&rdev->disable_work.work);
 	WARN_ON(rdev->open_count);
+	regulator_remove_coupling(rdev);
 	unset_regulator_supplies(rdev);
 	list_del(&rdev->list);
 	regulator_ena_gpio_free(rdev);
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 10/11] regulator: core: Use ww_mutex for regulators locking
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (8 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 09/11] regulator: core: Decouple regulators on regulator_unregister() Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-11-08 13:07   ` Mark Brown
  2018-10-05 15:36 ` [PATCH v1 11/11] regulator: core: Properly handle case where supply is the couple Dmitry Osipenko
  2018-10-08 17:58 ` [PATCH v1 00/11] Continuing the work on coupled regulators Tony Lindgren
  11 siblings, 1 reply; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Wait/wound mutex shall be used in order to avoid lockups on locking of
coupled regulators.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Suggested-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/regulator/core.c         | 401 +++++++++++++++++++++++--------
 include/linux/regulator/driver.h |   3 +-
 2 files changed, 307 insertions(+), 97 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 783ec9c74104..a3448636f334 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -50,6 +50,8 @@
 #define rdev_dbg(rdev, fmt, ...)					\
 	pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
 
+static DEFINE_WW_CLASS(regulator_ww_class);
+static DEFINE_MUTEX(regulator_nesting_mutex);
 static DEFINE_MUTEX(regulator_list_mutex);
 static LIST_HEAD(regulator_map_list);
 static LIST_HEAD(regulator_ena_gpio_list);
@@ -154,7 +156,7 @@ static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
 /**
  * regulator_lock_nested - lock a single regulator
  * @rdev:		regulator source
- * @subclass:		mutex subclass used for lockdep
+ * @ww_ctx:		w/w mutex acquire context
  *
  * This function can be called many times by one task on
  * a single regulator and its mutex will be locked only
@@ -162,24 +164,52 @@ static inline struct regulator_dev *rdev_get_supply(struct regulator_dev *rdev)
  * than the one, which initially locked the mutex, it will
  * wait on mutex.
  */
-static void regulator_lock_nested(struct regulator_dev *rdev,
-				  unsigned int subclass)
+static inline int regulator_lock_nested(struct regulator_dev *rdev,
+					struct ww_acquire_ctx *ww_ctx)
 {
-	if (!mutex_trylock(&rdev->mutex)) {
-		if (rdev->mutex_owner == current) {
+	bool lock = false;
+	int ret = 0;
+
+	mutex_lock(&regulator_nesting_mutex);
+
+	if (ww_ctx || !ww_mutex_trylock(&rdev->mutex)) {
+		if (rdev->mutex_owner == current)
 			rdev->ref_cnt++;
-			return;
+		else
+			lock = true;
+
+		if (lock) {
+			mutex_unlock(&regulator_nesting_mutex);
+			ret = ww_mutex_lock(&rdev->mutex, ww_ctx);
+			mutex_lock(&regulator_nesting_mutex);
 		}
-		mutex_lock_nested(&rdev->mutex, subclass);
+	} else {
+		lock = true;
 	}
 
-	rdev->ref_cnt = 1;
-	rdev->mutex_owner = current;
+	if (lock && ret != -EDEADLK) {
+		rdev->ref_cnt++;
+		rdev->mutex_owner = current;
+	}
+
+	mutex_unlock(&regulator_nesting_mutex);
+
+	return ret;
 }
 
-static inline void regulator_lock(struct regulator_dev *rdev)
+/**
+ * regulator_lock - lock a single regulator
+ * @rdev:		regulator source
+ *
+ * This function can be called many times by one task on
+ * a single regulator and its mutex will be locked only
+ * once. If a task, which is calling this function is other
+ * than the one, which initially locked the mutex, it will
+ * wait on mutex.
+ */
+static void regulator_lock(struct regulator_dev *rdev)
 {
-	regulator_lock_nested(rdev, 0);
+	regulator_lock_nested(rdev, NULL);
 }
 
 /**
@@ -191,50 +221,46 @@ static inline void regulator_lock(struct regulator_dev *rdev)
  */
 static void regulator_unlock(struct regulator_dev *rdev)
 {
-	if (rdev->ref_cnt != 0) {
-		rdev->ref_cnt--;
+	mutex_lock(&regulator_nesting_mutex);
 
-		if (!rdev->ref_cnt) {
-			rdev->mutex_owner = NULL;
-			mutex_unlock(&rdev->mutex);
-		}
+	if (--rdev->ref_cnt == 0) {
+		rdev->mutex_owner = NULL;
+		ww_mutex_unlock(&rdev->mutex);
 	}
+
+	WARN_ON_ONCE(rdev->ref_cnt < 0);
+
+	mutex_unlock(&regulator_nesting_mutex);
 }
 
-static int regulator_lock_recursive(struct regulator_dev *rdev,
-				    unsigned int subclass)
+static void regulator_unlock_recursive(struct regulator_dev *rdev,
+				       unsigned int n_coupled)
 {
 	struct regulator_dev *c_rdev;
 	int i;
 
-	for (i = 0; i < rdev->coupling_desc.n_coupled; i++) {
-		c_rdev = rdev->coupling_desc.coupled_rdevs[i];
+	for (i = n_coupled; i > 0; i--) {
+		c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1];
 
 		if (!c_rdev)
 			continue;
 
-		regulator_lock_nested(c_rdev, subclass++);
-
 		if (c_rdev->supply)
-			subclass =
-				regulator_lock_recursive(c_rdev->supply->rdev,
-							 subclass);
-	}
+			regulator_unlock_recursive(
+					c_rdev->supply->rdev,
+					c_rdev->coupling_desc.n_coupled);
 
-	return subclass;
+		regulator_unlock(c_rdev);
+	}
 }
 
-/**
- * regulator_unlock_dependent - unlock regulator's suppliers and coupled
- *				regulators
- * @rdev:			regulator source
- *
- * Unlock all regulators related with rdev by coupling or suppling.
- */
-static void regulator_unlock_dependent(struct regulator_dev *rdev)
+static int regulator_lock_recursive(struct regulator_dev *rdev,
+				    struct regulator_dev **new_contended_rdev,
+				    struct regulator_dev **old_contended_rdev,
+				    struct ww_acquire_ctx *ww_ctx)
 {
 	struct regulator_dev *c_rdev;
-	int i;
+	int i, err;
 
 	for (i = 0; i < rdev->coupling_desc.n_coupled; i++) {
 		c_rdev = rdev->coupling_desc.coupled_rdevs[i];
@@ -242,23 +268,95 @@ static void regulator_unlock_dependent(struct regulator_dev *rdev)
 		if (!c_rdev)
 			continue;
 
-		regulator_unlock(c_rdev);
+		if (c_rdev != *old_contended_rdev) {
+			err = regulator_lock_nested(c_rdev, ww_ctx);
+			if (err) {
+				if (err == -EDEADLK) {
+					*new_contended_rdev = c_rdev;
+					goto err_unlock;
+				}
 
-		if (c_rdev->supply)
-			regulator_unlock_dependent(c_rdev->supply->rdev);
+				/* shouldn't happen */
+				WARN_ON_ONCE(err != -EALREADY);
+			}
+		} else {
+			*old_contended_rdev = NULL;
+		}
+
+		if (c_rdev->supply) {
+			err = regulator_lock_recursive(c_rdev->supply->rdev,
+						       new_contended_rdev,
+						       old_contended_rdev,
+						       ww_ctx);
+			if (err) {
+				regulator_unlock(c_rdev);
+				goto err_unlock;
+			}
+		}
 	}
+
+	return 0;
+
+err_unlock:
+	regulator_unlock_recursive(rdev, i);
+
+	return err;
+}
+
+/**
+ * regulator_unlock_dependent - unlock regulator's suppliers and coupled
+ *				regulators
+ * @rdev:			regulator source
+ * @ww_ctx:			w/w mutex acquire context
+ *
+ * Unlock all regulators related with rdev by coupling or suppling.
+ */
+static void regulator_unlock_dependent(struct regulator_dev *rdev,
+				       struct ww_acquire_ctx *ww_ctx)
+{
+	regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled);
+	ww_acquire_fini(ww_ctx);
 }
 
 /**
  * regulator_lock_dependent - lock regulator's suppliers and coupled regulators
  * @rdev:			regulator source
+ * @ww_ctx:			w/w mutex acquire context
  *
  * This function as a wrapper on regulator_lock_recursive(), which locks
  * all regulators related with rdev by coupling or suppling.
  */
-static inline void regulator_lock_dependent(struct regulator_dev *rdev)
+static void regulator_lock_dependent(struct regulator_dev *rdev,
+				     struct ww_acquire_ctx *ww_ctx)
 {
-	regulator_lock_recursive(rdev, 0);
+	struct regulator_dev *new_contended_rdev = NULL;
+	struct regulator_dev *old_contended_rdev = NULL;
+	int err;
+
+	mutex_lock(&regulator_list_mutex);
+
+	ww_acquire_init(ww_ctx, &regulator_ww_class);
+
+	do {
+		if (new_contended_rdev) {
+			ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx);
+			old_contended_rdev = new_contended_rdev;
+			old_contended_rdev->ref_cnt++;
+		}
+
+		err = regulator_lock_recursive(rdev,
+					       &new_contended_rdev,
+					       &old_contended_rdev,
+					       ww_ctx);
+
+		if (old_contended_rdev)
+			regulator_unlock(old_contended_rdev);
+
+	} while (err == -EDEADLK);
+
+	ww_acquire_done(ww_ctx);
+
+	mutex_unlock(&regulator_list_mutex);
 }
 
 /**
@@ -772,7 +870,7 @@ static int drms_uA_update(struct regulator_dev *rdev)
 	int current_uA = 0, output_uV, input_uV, err;
 	unsigned int mode;
 
-	lockdep_assert_held_once(&rdev->mutex);
+	lockdep_assert_held_once(&rdev->mutex.base);
 
 	/*
 	 * first check to see if we can set modes at all, otherwise just
@@ -2274,7 +2372,20 @@ static int _regulator_enable(struct regulator_dev *rdev)
 {
 	int ret;
 
-	lockdep_assert_held_once(&rdev->mutex);
+	lockdep_assert_held_once(&rdev->mutex.base);
+
+	if (rdev->supply) {
+		ret = _regulator_enable(rdev->supply->rdev);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* balance only if there are regulators coupled */
+	if (rdev->coupling_desc.n_coupled > 1) {
+		ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+		if (ret < 0)
+			goto err_disable_supply;
+	}
 
 	/* check voltage and requested load before enabling */
 	if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS))
@@ -2285,18 +2396,20 @@ static int _regulator_enable(struct regulator_dev *rdev)
 		ret = _regulator_is_enabled(rdev);
 		if (ret == -EINVAL || ret == 0) {
 			if (!regulator_ops_is_valid(rdev,
-					REGULATOR_CHANGE_STATUS))
-				return -EPERM;
+					REGULATOR_CHANGE_STATUS)) {
+				ret = -EPERM;
+				goto err_disable_supply;
+			}
 
 			ret = _regulator_do_enable(rdev);
 			if (ret < 0)
-				return ret;
+				goto err_disable_supply;
 
 			_notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE,
 					     NULL);
 		} else if (ret < 0) {
 			rdev_err(rdev, "is_enabled() failed: %d\n", ret);
-			return ret;
+			goto err_disable_supply;
 		}
 		/* Fallthrough on positive return values - already enabled */
 	}
@@ -2304,6 +2417,12 @@ static int _regulator_enable(struct regulator_dev *rdev)
 	rdev->use_count++;
 
 	return 0;
+
+err_disable_supply:
+	if (rdev->supply)
+		_regulator_disable(rdev->supply->rdev);
+
+	return ret;
 }
 
 /**
@@ -2320,30 +2439,15 @@ static int _regulator_enable(struct regulator_dev *rdev)
 int regulator_enable(struct regulator *regulator)
 {
 	struct regulator_dev *rdev = regulator->rdev;
+	struct ww_acquire_ctx ww_ctx;
 	int ret = 0;
 
 	if (regulator->always_on)
 		return 0;
 
-	if (rdev->supply) {
-		ret = regulator_enable(rdev->supply);
-		if (ret != 0)
-			return ret;
-	}
-
-	regulator_lock_dependent(rdev);
-	/* balance only if there are regulators coupled */
-	if (rdev->coupling_desc.n_coupled > 1) {
-		ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
-		if (ret != 0)
-			goto unlock;
-	}
+	regulator_lock_dependent(rdev, &ww_ctx);
 	ret = _regulator_enable(rdev);
-unlock:
-	regulator_unlock_dependent(rdev);
-
-	if (ret != 0 && rdev->supply)
-		regulator_disable(rdev->supply);
+	regulator_unlock_dependent(rdev, &ww_ctx);
 
 	return ret;
 }
@@ -2385,7 +2489,7 @@ static int _regulator_disable(struct regulator_dev *rdev)
 {
 	int ret = 0;
 
-	lockdep_assert_held_once(&rdev->mutex);
+	lockdep_assert_held_once(&rdev->mutex.base);
 
 	if (WARN(rdev->use_count <= 0,
 		 "unbalanced disables for %s\n", rdev_get_name(rdev)))
@@ -2423,6 +2527,12 @@ static int _regulator_disable(struct regulator_dev *rdev)
 		rdev->use_count--;
 	}
 
+	if (ret == 0 && rdev->coupling_desc.n_coupled > 1)
+		ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+	if (ret == 0 && rdev->supply)
+		ret = _regulator_disable(rdev->supply->rdev);
+
 	return ret;
 }
 
@@ -2441,19 +2551,15 @@ static int _regulator_disable(struct regulator_dev *rdev)
 int regulator_disable(struct regulator *regulator)
 {
 	struct regulator_dev *rdev = regulator->rdev;
+	struct ww_acquire_ctx ww_ctx;
 	int ret = 0;
 
 	if (regulator->always_on)
 		return 0;
 
-	regulator_lock_dependent(rdev);
+	regulator_lock_dependent(rdev, &ww_ctx);
 	ret = _regulator_disable(rdev);
-	if (rdev->coupling_desc.n_coupled > 1)
-		regulator_balance_voltage(rdev, PM_SUSPEND_ON);
-	regulator_unlock_dependent(rdev);
-
-	if (ret == 0 && rdev->supply)
-		regulator_disable(rdev->supply);
+	regulator_unlock_dependent(rdev, &ww_ctx);
 
 	return ret;
 }
@@ -2464,7 +2570,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 {
 	int ret = 0;
 
-	lockdep_assert_held_once(&rdev->mutex);
+	lockdep_assert_held_once(&rdev->mutex.base);
 
 	ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
 			REGULATOR_EVENT_PRE_DISABLE, NULL);
@@ -2497,14 +2603,15 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 int regulator_force_disable(struct regulator *regulator)
 {
 	struct regulator_dev *rdev = regulator->rdev;
+	struct ww_acquire_ctx ww_ctx;
 	int ret;
 
-	regulator_lock_dependent(rdev);
+	regulator_lock_dependent(rdev, &ww_ctx);
 	regulator->uA_load = 0;
 	ret = _regulator_force_disable(regulator->rdev);
 	if (rdev->coupling_desc.n_coupled > 1)
 		regulator_balance_voltage(rdev, PM_SUSPEND_ON);
-	regulator_unlock_dependent(rdev);
+	regulator_unlock_dependent(rdev, &ww_ctx);
 
 	if (rdev->supply)
 		while (rdev->open_count--)
@@ -2518,9 +2625,10 @@ static void regulator_disable_work(struct work_struct *work)
 {
 	struct regulator_dev *rdev = container_of(work, struct regulator_dev,
 						  disable_work.work);
+	struct ww_acquire_ctx ww_ctx;
 	int count, i, ret;
 
-	regulator_lock(rdev);
+	regulator_lock_dependent(rdev, &ww_ctx);
 
 	BUG_ON(!rdev->deferred_disables);
 
@@ -2541,7 +2649,10 @@ static void regulator_disable_work(struct work_struct *work)
 			rdev_err(rdev, "Deferred disable failed: %d\n", ret);
 	}
 
-	regulator_unlock(rdev);
+	if (rdev->coupling_desc.n_coupled > 1)
+		regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+
+	regulator_unlock_dependent(rdev, &ww_ctx);
 
 	if (rdev->supply) {
 		for (i = 0; i < count; i++) {
@@ -2652,9 +2763,9 @@ int regulator_is_enabled(struct regulator *regulator)
 	if (regulator->always_on)
 		return 1;
 
-	regulator_lock_dependent(regulator->rdev);
+	regulator_lock(regulator->rdev);
 	ret = _regulator_is_enabled(regulator->rdev);
-	regulator_unlock_dependent(regulator->rdev);
+	regulator_unlock(regulator->rdev);
 
 	return ret;
 }
@@ -3268,7 +3379,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
 		int tmp_min = 0;
 		int tmp_max = INT_MAX;
 
-		lockdep_assert_held_once(&c_rdevs[i]->mutex);
+		lockdep_assert_held_once(&c_rdevs[i]->mutex.base);
 
 		ret = regulator_check_consumers(c_rdevs[i],
 						&tmp_min,
@@ -3479,14 +3590,15 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
  */
 int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
 {
-	int ret = 0;
+	struct ww_acquire_ctx ww_ctx;
+	int ret;
 
-	regulator_lock_dependent(regulator->rdev);
+	regulator_lock_dependent(regulator->rdev, &ww_ctx);
 
 	ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV,
 					     PM_SUSPEND_ON);
 
-	regulator_unlock_dependent(regulator->rdev);
+	regulator_unlock_dependent(regulator->rdev, &ww_ctx);
 
 	return ret;
 }
@@ -3558,18 +3670,19 @@ static int _regulator_set_suspend_voltage(struct regulator *regulator,
 int regulator_set_suspend_voltage(struct regulator *regulator, int min_uV,
 				  int max_uV, suspend_state_t state)
 {
-	int ret = 0;
+	struct ww_acquire_ctx ww_ctx;
+	int ret;
 
 	/* PM_SUSPEND_ON is handled by regulator_set_voltage() */
 	if (regulator_check_states(state) || state == PM_SUSPEND_ON)
 		return -EINVAL;
 
-	regulator_lock_dependent(regulator->rdev);
+	regulator_lock_dependent(regulator->rdev, &ww_ctx);
 
 	ret = _regulator_set_suspend_voltage(regulator, min_uV,
 					     max_uV, state);
 
-	regulator_unlock_dependent(regulator->rdev);
+	regulator_unlock_dependent(regulator->rdev, &ww_ctx);
 
 	return ret;
 }
@@ -3759,13 +3872,12 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
  */
 int regulator_get_voltage(struct regulator *regulator)
 {
+	struct ww_acquire_ctx ww_ctx;
 	int ret;
 
-	regulator_lock_dependent(regulator->rdev);
-
+	regulator_lock_dependent(regulator->rdev, &ww_ctx);
 	ret = _regulator_get_voltage(regulator->rdev);
-
-	regulator_unlock_dependent(regulator->rdev);
+	regulator_unlock_dependent(regulator->rdev, &ww_ctx);
 
 	return ret;
 }
@@ -4301,7 +4413,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
 				  unsigned long event, void *data)
 {
-	lockdep_assert_held_once(&rdev->mutex);
+	lockdep_assert_held_once(&rdev->mutex.base);
 
 	_notifier_call_chain(rdev, event, data);
 	return NOTIFY_DONE;
@@ -4669,7 +4781,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
 		rdev->dev.of_node = of_node_get(config->of_node);
 	}
 
-	mutex_init(&rdev->mutex);
+	ww_mutex_init(&rdev->mutex, &regulator_ww_class);
 	rdev->reg_data = config->driver_data;
 	rdev->owner = regulator_desc->owner;
 	rdev->desc = regulator_desc;
@@ -5026,8 +5138,6 @@ static void regulator_summary_show_subtree(struct seq_file *s,
 	if (!rdev)
 		return;
 
-	regulator_lock_nested(rdev, level);
-
 	opmode = _regulator_get_mode_unlocked(rdev);
 	seq_printf(s, "%*s%-*s %3d %4d %6d %7s ",
 		   level * 3 + 1, "",
@@ -5084,8 +5194,101 @@ static void regulator_summary_show_subtree(struct seq_file *s,
 
 	class_for_each_device(&regulator_class, NULL, &summary_data,
 			      regulator_summary_show_children);
+}
+
+struct summary_lock_data {
+	struct ww_acquire_ctx *ww_ctx;
+	struct regulator_dev **new_contended_rdev;
+	struct regulator_dev **old_contended_rdev;
+};
+
+static int regulator_summary_lock_one(struct device *dev, void *data)
+{
+	struct regulator_dev *rdev = dev_to_rdev(dev);
+	struct summary_lock_data *lock_data = data;
+	int ret = 0;
+
+	if (rdev != *lock_data->old_contended_rdev) {
+		ret = regulator_lock_nested(rdev, lock_data->ww_ctx);
+
+		if (ret == -EDEADLK)
+			*lock_data->new_contended_rdev = rdev;
+		else
+			WARN_ON_ONCE(ret);
+	} else {
+		*lock_data->old_contended_rdev = NULL;
+	}
+
+	return ret;
+}
+
+static int regulator_summary_unlock_one(struct device *dev, void *data)
+{
+	struct regulator_dev *rdev = dev_to_rdev(dev);
+	struct summary_lock_data *lock_data = data;
+
+	if (lock_data) {
+		if (rdev == *lock_data->new_contended_rdev)
+			return -EDEADLK;
+	}
 
 	regulator_unlock(rdev);
+
+	return 0;
+}
+
+static int regulator_summary_lock_all(struct ww_acquire_ctx *ww_ctx,
+				      struct regulator_dev **new_contended_rdev,
+				      struct regulator_dev **old_contended_rdev)
+{
+	struct summary_lock_data lock_data;
+	int ret;
+
+	lock_data.ww_ctx = ww_ctx;
+	lock_data.new_contended_rdev = new_contended_rdev;
+	lock_data.old_contended_rdev = old_contended_rdev;
+
+	ret = class_for_each_device(&regulator_class, NULL, &lock_data,
+				    regulator_summary_lock_one);
+	if (ret)
+		class_for_each_device(&regulator_class, NULL, &lock_data,
+				      regulator_summary_unlock_one);
+
+	return ret;
+}
+
+static void regulator_summary_lock(struct ww_acquire_ctx *ww_ctx)
+{
+	struct regulator_dev *new_contended_rdev = NULL;
+	struct regulator_dev *old_contended_rdev = NULL;
+	int err;
+
+	ww_acquire_init(ww_ctx, &regulator_ww_class);
+
+	do {
+		if (new_contended_rdev) {
+			ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx);
+			old_contended_rdev = new_contended_rdev;
+			old_contended_rdev->ref_cnt++;
+		}
+
+		err = regulator_summary_lock_all(ww_ctx,
+						 &new_contended_rdev,
+						 &old_contended_rdev);
+
+		if (old_contended_rdev)
+			regulator_unlock(old_contended_rdev);
+
+	} while (err == -EDEADLK);
+
+	ww_acquire_done(ww_ctx);
+}
+
+static void regulator_summary_unlock(struct ww_acquire_ctx *ww_ctx)
+{
+	class_for_each_device(&regulator_class, NULL, NULL,
+			      regulator_summary_unlock_one);
+	ww_acquire_fini(ww_ctx);
 }
 
 static int regulator_summary_show_roots(struct device *dev, void *data)
@@ -5101,12 +5304,18 @@ static int regulator_summary_show_roots(struct device *dev, void *data)
 
 static int regulator_summary_show(struct seq_file *s, void *data)
 {
+	struct ww_acquire_ctx ww_ctx;
+
 	seq_puts(s, " regulator                      use open bypass  opmode voltage current     min     max\n");
 	seq_puts(s, "---------------------------------------------------------------------------------------\n");
 
+	regulator_summary_lock(&ww_ctx);
+
 	class_for_each_device(&regulator_class, NULL, s,
 			      regulator_summary_show_roots);
 
+	regulator_summary_unlock(&ww_ctx);
+
 	return 0;
 }
 
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index a05d37d0efa1..e71f9c314426 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -20,6 +20,7 @@
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/regulator/consumer.h>
+#include <linux/ww_mutex.h>
 
 struct gpio_desc;
 struct regmap;
@@ -462,7 +463,7 @@ struct regulator_dev {
 	struct coupling_desc coupling_desc;
 
 	struct blocking_notifier_head notifier;
-	struct mutex mutex; /* consumer lock */
+	struct ww_mutex mutex; /* consumer lock */
 	struct task_struct *mutex_owner;
 	int ref_cnt;
 	struct module *owner;
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v1 11/11] regulator: core: Properly handle case where supply is the couple
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (9 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 10/11] regulator: core: Use ww_mutex for regulators locking Dmitry Osipenko
@ 2018-10-05 15:36 ` Dmitry Osipenko
  2018-10-08 17:58 ` [PATCH v1 00/11] Continuing the work on coupled regulators Tony Lindgren
  11 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-05 15:36 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Maciej Purski
  Cc: Thierry Reding, Jonathan Hunter, Peter De Schrijver, Lucas Stach,
	devicetree, linux-kernel, linux-tegra, linux-omap

Check whether supply regulator is the couple to avoid infinite recursion
during of locking.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 drivers/regulator/core.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index a3448636f334..46e816cb80b5 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -233,6 +233,21 @@ static void regulator_unlock(struct regulator_dev *rdev)
 	mutex_unlock(&regulator_nesting_mutex);
 }
 
+static bool regulator_supply_is_couple(struct regulator_dev *rdev)
+{
+	struct regulator_dev *c_rdev;
+	int i;
+
+	for (i = 1; i < rdev->coupling_desc.n_coupled; i++) {
+		c_rdev = rdev->coupling_desc.coupled_rdevs[i];
+
+		if (rdev->supply->rdev == c_rdev)
+			return true;
+	}
+
+	return false;
+}
+
 static void regulator_unlock_recursive(struct regulator_dev *rdev,
 				       unsigned int n_coupled)
 {
@@ -245,7 +260,7 @@ static void regulator_unlock_recursive(struct regulator_dev *rdev,
 		if (!c_rdev)
 			continue;
 
-		if (c_rdev->supply)
+		if (c_rdev->supply && !regulator_supply_is_couple(c_rdev))
 			regulator_unlock_recursive(
 					c_rdev->supply->rdev,
 					c_rdev->coupling_desc.n_coupled);
@@ -283,7 +298,7 @@ static int regulator_lock_recursive(struct regulator_dev *rdev,
 			*old_contended_rdev = NULL;
 		}
 
-		if (c_rdev->supply) {
+		if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {
 			err = regulator_lock_recursive(c_rdev->supply->rdev,
 						       new_contended_rdev,
 						       old_contended_rdev,
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 00/11] Continuing the work on coupled regulators
  2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
                   ` (10 preceding siblings ...)
  2018-10-05 15:36 ` [PATCH v1 11/11] regulator: core: Properly handle case where supply is the couple Dmitry Osipenko
@ 2018-10-08 17:58 ` Tony Lindgren
  2018-10-09  8:52   ` Dmitry Osipenko
  11 siblings, 1 reply; 23+ messages in thread
From: Tony Lindgren @ 2018-10-08 17:58 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Mark Brown, Rob Herring, Maciej Purski, Thierry Reding,
	Jonathan Hunter, Peter De Schrijver, Lucas Stach, devicetree,
	linux-kernel, linux-tegra, linux-omap

* Dmitry Osipenko <digetx@gmail.com> [181005 15:43]:
> 1. Re-worked the original "Add voltage balancing mechanism" patch from
>    Maciej by:
>         1) Fixing infinite loop within regulator_balance_voltage().
>         2) Handling suspend_state_t properly.
>         3) Fixing broken compilation of the patch.

Thanks for fixing these, this series no longer hangs for me
on beagle-x15.

Regards,

Tony

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 00/11] Continuing the work on coupled regulators
  2018-10-08 17:58 ` [PATCH v1 00/11] Continuing the work on coupled regulators Tony Lindgren
@ 2018-10-09  8:52   ` Dmitry Osipenko
  0 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-09  8:52 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Mark Brown, Rob Herring, Maciej Purski, Thierry Reding,
	Jonathan Hunter, Peter De Schrijver, Lucas Stach, devicetree,
	linux-kernel, linux-tegra, linux-omap

On 10/8/18 8:58 PM, Tony Lindgren wrote:
> * Dmitry Osipenko <digetx@gmail.com> [181005 15:43]:
>> 1. Re-worked the original "Add voltage balancing mechanism" patch from
>>    Maciej by:
>>         1) Fixing infinite loop within regulator_balance_voltage().
>>         2) Handling suspend_state_t properly.
>>         3) Fixing broken compilation of the patch.
> 
> Thanks for fixing these, this series no longer hangs for me
> on beagle-x15.

Thank you very much for testing once again!

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property
  2018-10-05 15:36 ` [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property Dmitry Osipenko
@ 2018-10-17 13:25   ` Rob Herring
  2018-10-17 13:32     ` Dmitry Osipenko
  2018-10-17 13:27   ` Rob Herring
  1 sibling, 1 reply; 23+ messages in thread
From: Rob Herring @ 2018-10-17 13:25 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Mark Brown, Maciej Purski, Thierry Reding, Jonathan Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On Fri, Oct 05, 2018 at 06:36:32PM +0300, Dmitry Osipenko wrote:
> Redefine binding for regulator-coupled-max-spread property in a way that
> max-spread values are defined per regulator couple instead of defining
> single max-spread for the whole group of coupled regulators.
> 
> With that change the following regulators coupling configuration will be
> possible:
> 
> regA: regulatorA {
> 	regulator-coupled-with = <&regB &regC>;
> 	regulator-coupled-max-spread = <100000 300000>;
> };
> 
> regB: regulatorB {
> 	regulator-coupled-with = <&regA &regC>;
> 	regulator-coupled-max-spread = <100000 200000>;
> };
> 
> regC: regulatorC {
> 	regulator-coupled-with = <&regA &regB>;
> 	regulator-coupled-max-spread = <300000 200000>;
> };
> 
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
>  Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
> index a7cd36877bfe..9b525b657fca 100644
> --- a/Documentation/devicetree/bindings/regulator/regulator.txt
> +++ b/Documentation/devicetree/bindings/regulator/regulator.txt
> @@ -76,8 +76,9 @@ Optional properties:
>  - regulator-coupled-with: Regulators with which the regulator
>    is coupled. The linkage is 2-way - all coupled regulators should be linked
>    with each other. A regulator should not be coupled with its supplier.
> -- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
> -  in microvolts.
> +- regulator-coupled-max-spread: Array of maximum spread between voltages of
> +  coupled regulators in microvolts, each value in the array relates to the
> +  corresponding couple specified by the regulator-coupled-with property.

Is this in use already? How is a single entry handled?

Rob

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property
  2018-10-05 15:36 ` [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property Dmitry Osipenko
  2018-10-17 13:25   ` Rob Herring
@ 2018-10-17 13:27   ` Rob Herring
  2018-10-17 13:31     ` Rob Herring
  1 sibling, 1 reply; 23+ messages in thread
From: Rob Herring @ 2018-10-17 13:27 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Mark Brown, Maciej Purski, Thierry Reding, Jonathan Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On Fri,  5 Oct 2018 18:36:32 +0300, Dmitry Osipenko wrote:
> Redefine binding for regulator-coupled-max-spread property in a way that
> max-spread values are defined per regulator couple instead of defining
> single max-spread for the whole group of coupled regulators.
> 
> With that change the following regulators coupling configuration will be
> possible:
> 
> regA: regulatorA {
> 	regulator-coupled-with = <&regB &regC>;
> 	regulator-coupled-max-spread = <100000 300000>;
> };
> 
> regB: regulatorB {
> 	regulator-coupled-with = <&regA &regC>;
> 	regulator-coupled-max-spread = <100000 200000>;
> };
> 
> regC: regulatorC {
> 	regulator-coupled-with = <&regA &regB>;
> 	regulator-coupled-max-spread = <300000 200000>;
> };
> 
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
>  Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property
  2018-10-17 13:27   ` Rob Herring
@ 2018-10-17 13:31     ` Rob Herring
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring @ 2018-10-17 13:31 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Mark Brown, Maciej Purski, Thierry Reding, Jon Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On Wed, Oct 17, 2018 at 8:27 AM Rob Herring <robh@kernel.org> wrote:
>
> On Fri,  5 Oct 2018 18:36:32 +0300, Dmitry Osipenko wrote:
> > Redefine binding for regulator-coupled-max-spread property in a way that
> > max-spread values are defined per regulator couple instead of defining
> > single max-spread for the whole group of coupled regulators.
> >
> > With that change the following regulators coupling configuration will be
> > possible:
> >
> > regA: regulatorA {
> >       regulator-coupled-with = <&regB &regC>;
> >       regulator-coupled-max-spread = <100000 300000>;
> > };
> >
> > regB: regulatorB {
> >       regulator-coupled-with = <&regA &regC>;
> >       regulator-coupled-max-spread = <100000 200000>;
> > };
> >
> > regC: regulatorC {
> >       regulator-coupled-with = <&regA &regB>;
> >       regulator-coupled-max-spread = <300000 200000>;
> > };
> >
> > Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> > ---
> >  Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> >
>
> Reviewed-by: Rob Herring <robh@kernel.org>

Sent this by mistake. Disregard as I have questions.

Rob

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property
  2018-10-17 13:25   ` Rob Herring
@ 2018-10-17 13:32     ` Dmitry Osipenko
  2018-10-17 13:33       ` Rob Herring
  0 siblings, 1 reply; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-17 13:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Brown, Maciej Purski, Thierry Reding, Jonathan Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On 10/17/18 4:25 PM, Rob Herring wrote:
> On Fri, Oct 05, 2018 at 06:36:32PM +0300, Dmitry Osipenko wrote:
>> Redefine binding for regulator-coupled-max-spread property in a way that
>> max-spread values are defined per regulator couple instead of defining
>> single max-spread for the whole group of coupled regulators.
>>
>> With that change the following regulators coupling configuration will be
>> possible:
>>
>> regA: regulatorA {
>> 	regulator-coupled-with = <&regB &regC>;
>> 	regulator-coupled-max-spread = <100000 300000>;
>> };
>>
>> regB: regulatorB {
>> 	regulator-coupled-with = <&regA &regC>;
>> 	regulator-coupled-max-spread = <100000 200000>;
>> };
>>
>> regC: regulatorC {
>> 	regulator-coupled-with = <&regA &regB>;
>> 	regulator-coupled-max-spread = <300000 200000>;
>> };
>>
>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
>> ---
>>  Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++--
>>  1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
>> index a7cd36877bfe..9b525b657fca 100644
>> --- a/Documentation/devicetree/bindings/regulator/regulator.txt
>> +++ b/Documentation/devicetree/bindings/regulator/regulator.txt
>> @@ -76,8 +76,9 @@ Optional properties:
>>  - regulator-coupled-with: Regulators with which the regulator
>>    is coupled. The linkage is 2-way - all coupled regulators should be linked
>>    with each other. A regulator should not be coupled with its supplier.
>> -- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
>> -  in microvolts.
>> +- regulator-coupled-max-spread: Array of maximum spread between voltages of
>> +  coupled regulators in microvolts, each value in the array relates to the
>> +  corresponding couple specified by the regulator-coupled-with property.
> 
> Is this in use already? How is a single entry handled?

No, it is not in use yet. Only some of the prerequisite patches were applied. 

Initially single entry was supposed to be re-used by all of regulator couples. Now single entry describes a single couple only.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property
  2018-10-17 13:32     ` Dmitry Osipenko
@ 2018-10-17 13:33       ` Rob Herring
  2018-10-17 13:36         ` Dmitry Osipenko
  0 siblings, 1 reply; 23+ messages in thread
From: Rob Herring @ 2018-10-17 13:33 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Mark Brown, Maciej Purski, Thierry Reding, Jon Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On Wed, Oct 17, 2018 at 8:32 AM Dmitry Osipenko <digetx@gmail.com> wrote:
>
> On 10/17/18 4:25 PM, Rob Herring wrote:
> > On Fri, Oct 05, 2018 at 06:36:32PM +0300, Dmitry Osipenko wrote:
> >> Redefine binding for regulator-coupled-max-spread property in a way that
> >> max-spread values are defined per regulator couple instead of defining
> >> single max-spread for the whole group of coupled regulators.
> >>
> >> With that change the following regulators coupling configuration will be
> >> possible:
> >>
> >> regA: regulatorA {
> >>      regulator-coupled-with = <&regB &regC>;
> >>      regulator-coupled-max-spread = <100000 300000>;
> >> };
> >>
> >> regB: regulatorB {
> >>      regulator-coupled-with = <&regA &regC>;
> >>      regulator-coupled-max-spread = <100000 200000>;
> >> };
> >>
> >> regC: regulatorC {
> >>      regulator-coupled-with = <&regA &regB>;
> >>      regulator-coupled-max-spread = <300000 200000>;
> >> };
> >>
> >> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> >> ---
> >>  Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++--
> >>  1 file changed, 3 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
> >> index a7cd36877bfe..9b525b657fca 100644
> >> --- a/Documentation/devicetree/bindings/regulator/regulator.txt
> >> +++ b/Documentation/devicetree/bindings/regulator/regulator.txt
> >> @@ -76,8 +76,9 @@ Optional properties:
> >>  - regulator-coupled-with: Regulators with which the regulator
> >>    is coupled. The linkage is 2-way - all coupled regulators should be linked
> >>    with each other. A regulator should not be coupled with its supplier.
> >> -- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
> >> -  in microvolts.
> >> +- regulator-coupled-max-spread: Array of maximum spread between voltages of
> >> +  coupled regulators in microvolts, each value in the array relates to the
> >> +  corresponding couple specified by the regulator-coupled-with property.
> >
> > Is this in use already? How is a single entry handled?
>
> No, it is not in use yet. Only some of the prerequisite patches were applied.

Please make that clear in the commit message.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 07/11] dt-bindings: regulator: Document new regulator-max-step-microvolt property
  2018-10-05 15:36 ` [PATCH v1 07/11] dt-bindings: regulator: Document new regulator-max-step-microvolt property Dmitry Osipenko
@ 2018-10-17 13:33   ` Rob Herring
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring @ 2018-10-17 13:33 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Mark Brown, Maciej Purski, Thierry Reding, Jonathan Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On Fri,  5 Oct 2018 18:36:34 +0300, Dmitry Osipenko wrote:
> Certain hardware may require supply voltage to be changed in steps. Define
> new property that allow to describe such hardware.
> 
> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
> ---
>  Documentation/devicetree/bindings/regulator/regulator.txt | 2 ++
>  1 file changed, 2 insertions(+)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property
  2018-10-17 13:33       ` Rob Herring
@ 2018-10-17 13:36         ` Dmitry Osipenko
  0 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-10-17 13:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Brown, Maciej Purski, Thierry Reding, Jon Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On 10/17/18 4:33 PM, Rob Herring wrote:
> On Wed, Oct 17, 2018 at 8:32 AM Dmitry Osipenko <digetx@gmail.com> wrote:
>>
>> On 10/17/18 4:25 PM, Rob Herring wrote:
>>> On Fri, Oct 05, 2018 at 06:36:32PM +0300, Dmitry Osipenko wrote:
>>>> Redefine binding for regulator-coupled-max-spread property in a way that
>>>> max-spread values are defined per regulator couple instead of defining
>>>> single max-spread for the whole group of coupled regulators.
>>>>
>>>> With that change the following regulators coupling configuration will be
>>>> possible:
>>>>
>>>> regA: regulatorA {
>>>>      regulator-coupled-with = <&regB &regC>;
>>>>      regulator-coupled-max-spread = <100000 300000>;
>>>> };
>>>>
>>>> regB: regulatorB {
>>>>      regulator-coupled-with = <&regA &regC>;
>>>>      regulator-coupled-max-spread = <100000 200000>;
>>>> };
>>>>
>>>> regC: regulatorC {
>>>>      regulator-coupled-with = <&regA &regB>;
>>>>      regulator-coupled-max-spread = <300000 200000>;
>>>> };
>>>>
>>>> Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
>>>> ---
>>>>  Documentation/devicetree/bindings/regulator/regulator.txt | 5 +++--
>>>>  1 file changed, 3 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
>>>> index a7cd36877bfe..9b525b657fca 100644
>>>> --- a/Documentation/devicetree/bindings/regulator/regulator.txt
>>>> +++ b/Documentation/devicetree/bindings/regulator/regulator.txt
>>>> @@ -76,8 +76,9 @@ Optional properties:
>>>>  - regulator-coupled-with: Regulators with which the regulator
>>>>    is coupled. The linkage is 2-way - all coupled regulators should be linked
>>>>    with each other. A regulator should not be coupled with its supplier.
>>>> -- regulator-coupled-max-spread: Max spread between voltages of coupled regulators
>>>> -  in microvolts.
>>>> +- regulator-coupled-max-spread: Array of maximum spread between voltages of
>>>> +  coupled regulators in microvolts, each value in the array relates to the
>>>> +  corresponding couple specified by the regulator-coupled-with property.
>>>
>>> Is this in use already? How is a single entry handled?
>>
>> No, it is not in use yet. Only some of the prerequisite patches were applied.
> 
> Please make that clear in the commit message.

Okay.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 10/11] regulator: core: Use ww_mutex for regulators locking
  2018-10-05 15:36 ` [PATCH v1 10/11] regulator: core: Use ww_mutex for regulators locking Dmitry Osipenko
@ 2018-11-08 13:07   ` Mark Brown
  2018-11-08 16:53     ` Dmitry Osipenko
  0 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2018-11-08 13:07 UTC (permalink / raw)
  To: Dmitry Osipenko
  Cc: Rob Herring, Maciej Purski, Thierry Reding, Jonathan Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

[-- Attachment #1: Type: text/plain, Size: 581 bytes --]

On Fri, Oct 05, 2018 at 06:36:37PM +0300, Dmitry Osipenko wrote:

> Wait/wound mutex shall be used in order to avoid lockups on locking of
> coupled regulators.

This breaks the build due to a few of the drivers (wm8350 and da9210 at
least) taking rdev locks in their interrupt handlers.  I'd suggest
adding a function for those drivers to use - exposing the ww context
seems like the wrong thing to do there.

Otherwise the series looks good, I've applied everything up to here.
Thanks for taking the time to pick this up, and especially for figuring
out the ww_mutex conversion.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v1 10/11] regulator: core: Use ww_mutex for regulators locking
  2018-11-08 13:07   ` Mark Brown
@ 2018-11-08 16:53     ` Dmitry Osipenko
  0 siblings, 0 replies; 23+ messages in thread
From: Dmitry Osipenko @ 2018-11-08 16:53 UTC (permalink / raw)
  To: Mark Brown
  Cc: Rob Herring, Maciej Purski, Thierry Reding, Jonathan Hunter,
	Peter De Schrijver, Lucas Stach, devicetree, linux-kernel,
	linux-tegra, linux-omap

On 08.11.2018 16:07, Mark Brown wrote:
> On Fri, Oct 05, 2018 at 06:36:37PM +0300, Dmitry Osipenko wrote:
> 
>> Wait/wound mutex shall be used in order to avoid lockups on locking of
>> coupled regulators.
> 
> This breaks the build due to a few of the drivers (wm8350 and da9210 at
> least) taking rdev locks in their interrupt handlers.  I'd suggest
> adding a function for those drivers to use - exposing the ww context
> seems like the wrong thing to do there.

I totally missed those drivers, will fix them in v2.

> Otherwise the series looks good, I've applied everything up to here.
> Thanks for taking the time to pick this up, and especially for figuring
> out the ww_mutex conversion.
> 

Thank you.

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2018-11-08 16:54 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-05 15:36 [PATCH v1 00/11] Continuing the work on coupled regulators Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 01/11] regulator: core: Add voltage balancing mechanism Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 02/11] regulator: core: Change voltage setting path Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 03/11] regulator: core: Mutually resolve regulators coupling Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 04/11] regulator: core: Don't allow to get regulator until all couples resolved Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 05/11] dt-bindings: regulator: Change regulator-coupled-max-spread property Dmitry Osipenko
2018-10-17 13:25   ` Rob Herring
2018-10-17 13:32     ` Dmitry Osipenko
2018-10-17 13:33       ` Rob Herring
2018-10-17 13:36         ` Dmitry Osipenko
2018-10-17 13:27   ` Rob Herring
2018-10-17 13:31     ` Rob Herring
2018-10-05 15:36 ` [PATCH v1 06/11] regulator: core: Limit regulators coupling to a single couple Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 07/11] dt-bindings: regulator: Document new regulator-max-step-microvolt property Dmitry Osipenko
2018-10-17 13:33   ` Rob Herring
2018-10-05 15:36 ` [PATCH v1 08/11] regulator: core: Add new max_uV_step constraint Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 09/11] regulator: core: Decouple regulators on regulator_unregister() Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 10/11] regulator: core: Use ww_mutex for regulators locking Dmitry Osipenko
2018-11-08 13:07   ` Mark Brown
2018-11-08 16:53     ` Dmitry Osipenko
2018-10-05 15:36 ` [PATCH v1 11/11] regulator: core: Properly handle case where supply is the couple Dmitry Osipenko
2018-10-08 17:58 ` [PATCH v1 00/11] Continuing the work on coupled regulators Tony Lindgren
2018-10-09  8:52   ` Dmitry Osipenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).