Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27756ae3 authored by Rui Zhang's avatar Rui Zhang Committed by Greg Kroah-Hartman
Browse files

regulator: core: Only increment use_count when enable_count changes



[ Upstream commit 7993d3a9c34f609c02171e115fd12c10e2105ff4 ]

The use_count of a regulator should only be incremented when the
enable_count changes from 0 to 1. Similarly, the use_count should
only be decremented when the enable_count changes from 1 to 0.

In the previous implementation, use_count was sometimes decremented
to 0 when some consumer called unbalanced disable,
leading to unexpected disable even the regulator is enabled by
other consumers. With this change, the use_count accurately reflects
the number of users which the regulator is enabled.

This should make things more robust in the case where a consumer does
leak references.

Signed-off-by: default avatarRui Zhang <zr.zhang@vivo.com>
Link: https://lore.kernel.org/r/20231103074231.8031-1-zr.zhang@vivo.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent aed181fb
Loading
Loading
Loading
Loading
+30 −26
Original line number Diff line number Diff line
@@ -2658,6 +2658,7 @@ static int _regulator_enable(struct regulator *regulator)
		/* Fallthrough on positive return values - already enabled */
	}

	if (regulator->enable_count == 1)
		rdev->use_count++;

	return 0;
@@ -2736,10 +2737,12 @@ static int _regulator_disable(struct regulator *regulator)

	lockdep_assert_held_once(&rdev->mutex.base);

	if (WARN(rdev->use_count <= 0,
	if (WARN(regulator->enable_count == 0,
		 "unbalanced disables for %s\n", rdev_get_name(rdev)))
		return -EIO;

	if (regulator->enable_count == 1) {
	/* disabling last enable_count from this regulator */
		/* are we the last user and permitted to disable ? */
		if (rdev->use_count == 1 &&
		    (rdev->constraints && !rdev->constraints->always_on)) {
@@ -2768,6 +2771,7 @@ static int _regulator_disable(struct regulator *regulator)
		} else if (rdev->use_count > 1) {
			rdev->use_count--;
		}
	}

	if (ret == 0)
		ret = _regulator_handle_consumer_disable(regulator);