mirror of
https://github.com/torvalds/linux.git
synced 2026-08-01 03:59:40 +02:00
clk: qcom: Fix race condition when unvoting regulators in sync_state
Normally clk_vote_vdd_level() and clk_unvote_vdd_level() are called while holding the clock framework's prepare_lock since they are called in the prepare paths. However, we're also calling clk_unvote_vdd_level() from qcom_cc_sync_state() when removing proxy votes. This happens outside of the clock framework, so the prepare_lock isn't protecting this case. If the sync_state callback fires while another thread is voting/unvoting voltage from a normal clock call, then there's a race condition that can result in regulators being set to the incorrect voltage or being pre-maturely disabled. Add a mutex to protect this case. Change-Id: Ib979e2edaaa5824dc80f7d4f065d72ca0b1a4444 Signed-off-by: Mike Tipton <mdtipton@codeaurora.org>
This commit is contained in:
parent
2ffa8360f4
commit
9bb68c3604
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "vdd-class.h"
|
||||
|
||||
static DEFINE_MUTEX(vdd_lock);
|
||||
|
||||
/*
|
||||
* Aggregate the vdd_class level votes and call regulator framework functions
|
||||
* to enforce the highest vote.
|
||||
|
|
@ -86,12 +88,15 @@ int clk_vote_vdd_level(struct clk_vdd_class_data *vdd_data, int level)
|
|||
if (level >= vdd_class->num_levels)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&vdd_lock);
|
||||
vdd_class->level_votes[level]++;
|
||||
|
||||
ret = clk_aggregate_vdd(vdd_class);
|
||||
if (ret)
|
||||
vdd_class->level_votes[level]--;
|
||||
|
||||
mutex_unlock(&vdd_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_vote_vdd_level);
|
||||
|
|
@ -121,12 +126,15 @@ int clk_unvote_vdd_level(struct clk_vdd_class_data *vdd_data, int level)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&vdd_lock);
|
||||
vdd_class->level_votes[level]--;
|
||||
|
||||
ret = clk_aggregate_vdd(vdd_class);
|
||||
if (ret)
|
||||
vdd_class->level_votes[level]++;
|
||||
|
||||
mutex_unlock(&vdd_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_unvote_vdd_level);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user