mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 21:52:04 +00:00
regulator: Avoid grabbing regulator lock during suspend/resume
I see it takes about 5us per regulator to grab the lock, check that this regulator isn't going to do anything for suspend, and then release the lock. When that is combined with PMICs that have dozens of regulators we get into a state where we spend a few miliseconds doing a bunch of locking operations synchronously to figure out that there's nothing to do. Let's reorganize the code here a bit so that we don't grab the lock until we're actually going to do something so that suspend is a little faster. Signed-off-by: Stephen Boyd <swboyd@chromium.org> Reviewed-by: Douglas Anderson <dianders@chromium.org> Cc: Matthias Kaehlcke <mka@chromium.org> Cc: Douglas Anderson <dianders@chromium.org> Link: https://lore.kernel.org/r/20200804070837.1084024-1-swboyd@chromium.org Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
a16138a32e
commit
0955f5be43
@ -565,6 +565,30 @@ regulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state)
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regulator_state *
|
||||
regulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t state)
|
||||
{
|
||||
const struct regulator_state *rstate;
|
||||
|
||||
rstate = regulator_get_suspend_state(rdev, state);
|
||||
if (rstate == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If we have no suspend mode configuration don't set anything;
|
||||
* only warn if the driver implements set_suspend_voltage or
|
||||
* set_suspend_mode callback.
|
||||
*/
|
||||
if (rstate->enabled != ENABLE_IN_SUSPEND &&
|
||||
rstate->enabled != DISABLE_IN_SUSPEND) {
|
||||
if (rdev->desc->ops->set_suspend_voltage ||
|
||||
rdev->desc->ops->set_suspend_mode)
|
||||
rdev_warn(rdev, "No configuration\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rstate;
|
||||
}
|
||||
|
||||
static ssize_t regulator_uV_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -982,27 +1006,10 @@ static int drms_uA_update(struct regulator_dev *rdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int suspend_set_state(struct regulator_dev *rdev,
|
||||
suspend_state_t state)
|
||||
static int __suspend_set_state(struct regulator_dev *rdev,
|
||||
const struct regulator_state *rstate)
|
||||
{
|
||||
int ret = 0;
|
||||
struct regulator_state *rstate;
|
||||
|
||||
rstate = regulator_get_suspend_state(rdev, state);
|
||||
if (rstate == NULL)
|
||||
return 0;
|
||||
|
||||
/* If we have no suspend mode configuration don't set anything;
|
||||
* only warn if the driver implements set_suspend_voltage or
|
||||
* set_suspend_mode callback.
|
||||
*/
|
||||
if (rstate->enabled != ENABLE_IN_SUSPEND &&
|
||||
rstate->enabled != DISABLE_IN_SUSPEND) {
|
||||
if (rdev->desc->ops->set_suspend_voltage ||
|
||||
rdev->desc->ops->set_suspend_mode)
|
||||
rdev_warn(rdev, "No configuration\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rstate->enabled == ENABLE_IN_SUSPEND &&
|
||||
rdev->desc->ops->set_suspend_enable)
|
||||
@ -1037,6 +1044,18 @@ static int suspend_set_state(struct regulator_dev *rdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int suspend_set_initial_state(struct regulator_dev *rdev)
|
||||
{
|
||||
const struct regulator_state *rstate;
|
||||
|
||||
rstate = regulator_get_suspend_state_check(rdev,
|
||||
rdev->constraints->initial_state);
|
||||
if (!rstate)
|
||||
return 0;
|
||||
|
||||
return __suspend_set_state(rdev, rstate);
|
||||
}
|
||||
|
||||
static void print_constraints(struct regulator_dev *rdev)
|
||||
{
|
||||
struct regulation_constraints *constraints = rdev->constraints;
|
||||
@ -1319,7 +1338,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
|
||||
|
||||
/* do we need to setup our suspend state */
|
||||
if (rdev->constraints->initial_state) {
|
||||
ret = suspend_set_state(rdev, rdev->constraints->initial_state);
|
||||
ret = suspend_set_initial_state(rdev);
|
||||
if (ret < 0) {
|
||||
rdev_err(rdev, "failed to set suspend state\n");
|
||||
return ret;
|
||||
@ -5362,9 +5381,14 @@ static int regulator_suspend(struct device *dev)
|
||||
struct regulator_dev *rdev = dev_to_rdev(dev);
|
||||
suspend_state_t state = pm_suspend_target_state;
|
||||
int ret;
|
||||
const struct regulator_state *rstate;
|
||||
|
||||
rstate = regulator_get_suspend_state_check(rdev, state);
|
||||
if (!rstate)
|
||||
return 0;
|
||||
|
||||
regulator_lock(rdev);
|
||||
ret = suspend_set_state(rdev, state);
|
||||
ret = __suspend_set_state(rdev, rstate);
|
||||
regulator_unlock(rdev);
|
||||
|
||||
return ret;
|
||||
@ -5381,11 +5405,14 @@ static int regulator_resume(struct device *dev)
|
||||
if (rstate == NULL)
|
||||
return 0;
|
||||
|
||||
/* Avoid grabbing the lock if we don't need to */
|
||||
if (!rdev->desc->ops->resume)
|
||||
return 0;
|
||||
|
||||
regulator_lock(rdev);
|
||||
|
||||
if (rdev->desc->ops->resume &&
|
||||
(rstate->enabled == ENABLE_IN_SUSPEND ||
|
||||
rstate->enabled == DISABLE_IN_SUSPEND))
|
||||
if (rstate->enabled == ENABLE_IN_SUSPEND ||
|
||||
rstate->enabled == DISABLE_IN_SUSPEND)
|
||||
ret = rdev->desc->ops->resume(rdev);
|
||||
|
||||
regulator_unlock(rdev);
|
||||
|
Loading…
Reference in New Issue
Block a user