On Tue, Mar 20, 2012 at 7:02 AM, Shawn Guo <shawn....@linaro.org> wrote: > On Thu, Mar 15, 2012 at 11:11:19PM -0700, Mike Turquette wrote: > ... >> +struct clk_ops { >> + int (*prepare)(struct clk_hw *hw); >> + void (*unprepare)(struct clk_hw *hw); >> + int (*enable)(struct clk_hw *hw); >> + void (*disable)(struct clk_hw *hw); >> + int (*is_enabled)(struct clk_hw *hw); >> + unsigned long (*recalc_rate)(struct clk_hw *hw, >> + unsigned long parent_rate); > > I believe I have heard people love the interface with parent_rate > passed in. I love that too. But I would like to ask the same thing > on .round_rate and .set_rate as well for the same reason why we have > it for .recalc_rate.
This is something that was discussed on the list but not taken in due to rapid flux in code. I always liked the idea however. > >> + long (*round_rate)(struct clk_hw *hw, unsigned long, >> + unsigned long *); > > Yes, we already have parent_rate passed in .round_rate with an pointer. > But I think it'd be better to have it passed in no matter flag > CLK_SET_RATE_PARENT is set or not. Something like: This places the burden of checking the flags onto the .round_rate implementation with __clk_get_flags, but that's not a problem really. > > 8<--- > @@ -584,7 +584,7 @@ EXPORT_SYMBOL_GPL(clk_get_rate); > */ > unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) > { > - unsigned long unused; > + unsigned long parent_rate = 0; > > if (!clk) > return -EINVAL; > @@ -592,10 +592,10 @@ unsigned long __clk_round_rate(struct clk *clk, > unsigned long rate) > if (!clk->ops->round_rate) > return clk->rate; > > - if (clk->flags & CLK_SET_RATE_PARENT) > - return clk->ops->round_rate(clk->hw, rate, &unused); > - else > - return clk->ops->round_rate(clk->hw, rate, NULL); > + if (clk->parent) > + parent_rate = clk->parent->rate; > + > + return clk->ops->round_rate(clk->hw, rate, &parent_rate); > } > > /** > @@ -765,9 +765,12 @@ static void clk_calc_subtree(struct clk *clk, unsigned > long new_rate) > static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) > { > struct clk *top = clk; > - unsigned long best_parent_rate = clk->parent->rate; > + unsigned long best_parent_rate = 0; > unsigned long new_rate; > > + if (clk->parent) > + best_parent_rate = clk->parent->rate; > + > if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) { > clk->new_rate = clk->rate; > return NULL; > @@ -780,10 +783,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, > unsigned long rate) > goto out; > } > > - if (clk->flags & CLK_SET_RATE_PARENT) > - new_rate = clk->ops->round_rate(clk->hw, rate, > &best_parent_rate); > - else > - new_rate = clk->ops->round_rate(clk->hw, rate, NULL); > + new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); > > if (best_parent_rate != clk->parent->rate) { > top = clk_calc_new_rates(clk->parent, best_parent_rate); > > --->8 ACK > > The reason behind the change is that any clk implements .round_rate will > mostly need to get the parent rate, no matter flag CLK_SET_RATE_PARENT > is set or not. Instead of expecting every .round_rate implementation > to get the parent rate in the way beloe > > parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); > > we can just pass the parent rate into .round_rate. > >> + int (*set_parent)(struct clk_hw *hw, u8 index); >> + u8 (*get_parent)(struct clk_hw *hw); >> + int (*set_rate)(struct clk_hw *hw, unsigned long); > > For the same reason, I would change .set_rate interface like below. > > 8<--- > > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c > index d5ac6a7..6bd8037 100644 > --- a/drivers/clk/clk-divider.c > +++ b/drivers/clk/clk-divider.c > @@ -119,7 +119,8 @@ static long clk_divider_round_rate(struct clk_hw *hw, > unsigned long rate, > } > EXPORT_SYMBOL_GPL(clk_divider_round_rate); > > -static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) > +static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > { > struct clk_divider *divider = to_clk_divider(hw); > unsigned int div; > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c > index dbc310a..d74ac4b 100644 > --- a/drivers/clk/clk.c > +++ b/drivers/clk/clk.c > @@ -833,17 +833,18 @@ static struct clk *clk_propagate_rate_change(struct clk > *clk, unsigned long even > static void clk_change_rate(struct clk *clk) > { > struct clk *child; > - unsigned long old_rate; > + unsigned long old_rate, parent_rate = 0; > struct hlist_node *tmp; > > old_rate = clk->rate; > + if (clk->parent) > + parent_rate = clk->parent->rate; > > if (clk->ops->set_rate) > - clk->ops->set_rate(clk->hw, clk->new_rate); > + clk->ops->set_rate(clk->hw, clk->new_rate, parent_rate); > > if (clk->ops->recalc_rate) > - clk->rate = clk->ops->recalc_rate(clk->hw, > - clk->parent->rate); > + clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate); > else > clk->rate = clk->parent->rate; > > diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h > index 5508897..1031f1f 100644 > --- a/include/linux/clk-provider.h > +++ b/include/linux/clk-provider.h > @@ -125,7 +125,8 @@ struct clk_ops { > unsigned long *); > int (*set_parent)(struct clk_hw *hw, u8 index); > u8 (*get_parent)(struct clk_hw *hw); > - int (*set_rate)(struct clk_hw *hw, unsigned long); > + int (*set_rate)(struct clk_hw *hw, unsigned long, > + unsigned long); > void (*init)(struct clk_hw *hw); > }; > > --->8 ACK > > Then with parent rate passed into .round_rate and .set_rate like what > we do with .recalc_rate right now, we can save particular clk > implementation from calling __clk_get_parent() and __clk_get_rate to > get parent rate. > > For example, the following will the be diff we gain on clk-divider. > > 8<--- > > diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c > index 6bd8037..8a28ffb 100644 > --- a/drivers/clk/clk-divider.c > +++ b/drivers/clk/clk-divider.c > @@ -68,8 +68,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned > long rate, > if (divider->flags & CLK_DIVIDER_ONE_BASED) > maxdiv--; > > - if (!best_parent_rate) { > - parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); > + if (!(divider->flags & CLK_SET_RATE_PARENT)) { This is wrong. CLK_SET_RATE_PARENT is a common clock flag applied to struct clk's .flags member, not the divider. This function must still use __clk_get_flags(hw->clk) here, but that's OK. > + parent_rate = *best_parent_rate; > bestdiv = DIV_ROUND_UP(parent_rate, rate); > bestdiv = bestdiv == 0 ? 1 : bestdiv; > bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; > @@ -109,13 +109,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, > unsigned long rate, > int div; > div = clk_divider_bestdiv(hw, rate, prate); > > - if (prate) > - return *prate / div; > - else { > - unsigned long r; > - r = __clk_get_rate(__clk_get_parent(hw->clk)); > - return r / div; > - } > + return *prate / div; > } > EXPORT_SYMBOL_GPL(clk_divider_round_rate); > > @@ -127,7 +121,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, > unsigned long rate, > unsigned long flags = 0; > u32 val; > > - div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; > + div = parent_rate / rate; > > if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) > div--; > > --->8 ACK, besides my comment above. > > I always get a sense of worry in using functions named in __xxx which > sounds like something somehow internal. With the requested interface > change above, I can get all __xxx functions out of my clk_ops > implementation. As mentioned above, you'll still need to check for CLK_SET_RATE_PARENT in your .round_rate implementation with __clk_get_flags(hw->clk). Did you want to send a formal patch or just have me absorb this into the fixes I'm brewing already? I've already fixed the potential null ptr dereferences in clk_calc_new_rates, but that's no big deal. Regards, Mike _______________________________________________ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev