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

Skip to content
Commit fa9b3044 authored by David Collins's avatar David Collins
Browse files

clk: correct vdd_class voting scheme used during clock rate changes



Correct the method used to account for vdd_class voltage level
requirements for each clock during a clk_set_rate() call.
This ensures that the ref count for each level does not
become out of sync during reentrant clk_set_rate() calls
or during complex rate change and re-parenting situations.

Implement the following behavior for clocks which have a
vdd_class specified:

clk_core_prepare():
- Calculate the voltage level needed for core->rate
- Vote for this voltage level
- Set both vdd_class_vote and new_vdd_class_vote to this level

clk_core_unprepare():
- Unvote for core->vdd_class_vote
- Set both vdd_class_vote and new_vdd_class_vote to 0

clk_core_set_rate_nolock() (and the helper functions it calls):
- While traversing the clock tree and calculating core->new_rate
  for each affected clock:
  - Calculate next_level that is needed for core->new_rate
  - If next_level != core->new_vdd_class_vote:
    - Vote for next_level
    - Insert core->rate_change_node into clk_rate_change_list
    - If rate_change_node is already in the list, then
      Unvote core->new_vdd_class_vote since it is being changed
    - Set core->new_vdd_class_vote = next_level

- If an error is encountered *before* any physical clock rates
  are changed, then loop over all clocks in clk_rate_change_list:
  - Unvote for core->new_vdd_class_vote
  - Set core->new_vdd_class_vote = core->vdd_class_vote
  - Remove core->rate_change_node from the list

- If an error is encountered *after* any physical clock rates
  are changed, then loop over all clocks in clk_rate_change_list:
  - If core->vdd_class_vote > core->new_vdd_class_vote:
    - Vote for core->vdd_class_vote
    - Unvote for core->new_vdd_class_vote
    - Set core->new_vdd_class_vote = core->vdd_class_vote
    - This ensures that the maximum voltage level needed for
      either core->rate or core->new_rate is configured since
      the physical state of the clock isn't well known after
      an error.
  - Unvote for core->vdd_class_vote
  - Set core->vdd_class_vote = core->new_vdd_class_vote
  - Remove core->rate_change_node from the list

- If all physical clock rates are changed successfully (including
  in reentrant clk_core_set_rate_nolock() calls), then loop over
  all clocks in clk_rate_change_list:
  - Unvote for core->vdd_class_vote
  - Set core->vdd_class_vote = core->new_vdd_class_vote
  - Remove core->rate_change_node from the list

Since clk_rate_change_list is shared between the original
invocation of clk_core_set_rate_nolock() and reentrant calls
to the function resulting from set_rate() callback ops that
explicitly call clk_set_rate(), special care must be taken
when inserting and removing elements.  Insertions must occur
atomically with new_vdd_class_vote voting.  Removals must only
occur from the original invocation of clk_core_set_rate_nolock()
and not in the reentrant calls.  Use a static nesting count to
tell the original and reentrant calls apart.

Change-Id: I3bfebf20101a0bf22a79a33188a63dfff0af11cc
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent a4c24b35
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment