[PATCH 02/11] clk: Implement clk_set_rate

Turquette, Mike mturquette at ti.com
Fri Aug 26 19:45:03 EDT 2011


On Wed, Aug 24, 2011 at 6:15 AM, Mark Brown
<broonie at opensource.wolfsonmicro.com> wrote:
> From: Jeremy Kerr <jeremy.kerr at canonical.com>
>
> Implemenent clk_set_rate by adding a set_rate callback to clk_hw_ops,
> and core code to handle propagation of rate changes up and down the
> clock tree.

Propagating rates up the tree is wrong.  If a parent rate must be
changed then clk_set_rate should be called on the parent explicitly,
then clk_set_rate can be called on the target child clk.

I don't see any other way to do it that is safe, save for some batch
operation mechanism that takes predefined clock sub-trees into account
(which is likely only feasible for SoCs since their data manuals
provide all this info).

> +/*
> + * clk_recalc_rates - Given a clock (with a recently updated clk->rate),
> + *     notify its children that the rate may need to be recalculated, using
> + *     ops->recalc_rate().
> + */
> +static void clk_recalc_rates(struct clk *clk)
> +{
> +       struct hlist_node *tmp;
> +       struct clk *child;
> +
> +       if (clk->ops->recalc_rate)
> +               clk->rate = clk->ops->recalc_rate(clk->hw);
> +
> +       hlist_for_each_entry(child, tmp, &clk->children, child_node)
> +               clk_recalc_rates(child);

We need a rate post-change notifier here that drivers can subscribe
to.  Since many devices do not support having their clocks changed on
the fly while the device is enabled, a pre-change and post-change
notifier are necessary to notify devices downstream of the clock being
changed.  Imagine doing a rate change high up in the tree (PLL) and
you can see that many devices will need these notifiers propagated to
them.

> +}
> +
>  int clk_set_rate(struct clk *clk, unsigned long rate)
>  {
> -       /* not yet implemented */
> -       return -ENOSYS;
> +       unsigned long parent_rate, new_rate;
> +       int ret;
> +
> +       if (!clk->ops->set_rate)
> +               return -ENOSYS;
> +
> +       new_rate = rate;
> +
> +       /* prevent racing with updates to the clock topology */
> +       mutex_lock(&prepare_lock);
> +
> +propagate:

Need a rate pre-change notifier here that walks the tree.  Drivers
subscribing to this notifier can save context and call their
pm_runtime_put or clk_disable bits so that they can survive the rate
change without any glitches before the rate actually changes.

> +       ret = clk->ops->set_rate(clk->hw, new_rate, &parent_rate);
> +
> +       if (ret < 0)
> +               return ret;
> +
> +       /* ops->set_rate may require the parent's rate to change (to
> +        * parent_rate), we need to propagate the set_rate call to the
> +        * parent.
> +        */
> +       if (ret == CLK_SET_RATE_PROPAGATE) {
> +               new_rate = parent_rate;
> +               clk = clk->parent;
> +               goto propagate;
> +       }

Again, I feel this is wrong.  Rate change propagation should only flow
downstream.  Any rate change arbitration that requires changes
upstream should be considered and handled by the driver.

> +
> +       /* If successful (including propagation to the parent clock(s)),
> +        * recalculate the rates of the clock, including children.  We'll be
> +        * calling this on the 'parent-most' clock that we propagated to.
> +        */
> +       clk_recalc_rates(clk);

As mentioned above, recalc should propagate rate post-change notification.

Regards,
Mike



More information about the linux-arm-kernel mailing list