Hi all,
> I suggested that clk_prepare() be callable only from non-atomic contexts,
> and do whatever's required to ensure that the clock is available. That
> may end up enabling the clock as a result.
I think that clk_prepare/clk_unprepare looks like the most promising solution,
so will try to get some preliminary patches done. Here's what I'm planning:
-----
The changes to the API are essentially:
1) Document clk_enable/clk_disable as callable from atomic contexts, and
so clock implementations must not sleep within this function.
2) For clock implementations that may sleep to turn on a clock, we add a
new pair of functions to the clock API: clk_prepare and clk_unprepare.
These will provide hooks for the clock implmentation to do any sleepable
work (eg, wait for PLLs to settle) in preparation for a later clk_enable.
For the most common clock implemntation cases (where clocks can be enabled
atomically), these functions will be a no-op, and all of the enable/disable
work can be done in clk_enable/clk_disable.
For implementations where clocks require blocking on enable/disable, most
of the work will be done in clk_prepare/clk_unprepare. The clk_enable
and clk_disable functions may be no-ops.
For drivers, this means that clk_prepare must be called (and have returned)
before calling clk_enable.
== Enable/Prepare counts ==
I intend to do the enable and prepare "counting" in the core clock API,
meaning that that the clk_ops callbacks will only invoked on the first
prepare/enable and the last unprepare/disable.
== Concurrency ==
Splitting the prepare and enable stages introduces the concurrency
requirements:
1) clk_enable must not return before the clock is outputting a valid clock
signal.
2) clk_prepare must not return before the clock is fully prepared (ie, it is
safe to call clk_enable).
It is not possible for clk_enable to wait for the clock to be prepared,
because that would require synchronisation with clk_prepare, which may then
require blocking. Therefore:
3) The clock consumer *must* respect the proper ordering of clk_prepare and
clk_enable. For example, drivers that call clk_enable during an interrupt
must ensure that the interrupt handler will not be invoked until
clk_prepare has returned.
== Other considerations ==
The time that a clock spends "prepared" is a superset of the the time that a
clock spends "enabled". Therefore, clocks that are switched on during
clk_prepare (ie, non-atomic clocks) will be running for a larger amount of
time. In some cases, this can be mitigated by moving some of the final
(atomic) switching functionality to the clk_enable function.
== Implementation ==
Basically:
struct clk {
const struct clk_ops *ops
int enable_count;
spinlock_t enable_lock;
int prepare_count;
struct mutex prepare_lock;
};
int clk_enable(struct clk *clk)
{
int ret = 0;
spin_lock(&clk->enable_lock);
if (!clk->enable_count)
ret = clk->ops->enable(clk);
if (!ret)
clk->enable_count++;
spin_unlock(&clk->enable_lock);
return ret;
}
int clk_prepare(struct clk *clk)
{
int ret = 0;
mutex_lock(&clk->prepare_lock);
if (!clk->prepare_count)
ret = clk->ops->prepare(clk);
if (!ret)
clk->prepare_count++;
mutex_unlock(&clk->prepare_lock);
return ret;
}
-----
Comments welcome, code coming soon.
Cheers,
Jeremy
Hello Jeremy,
On Tue, Feb 01, 2011 at 05:11:29PM +0800, Jeremy Kerr wrote:
> > I suggested that clk_prepare() be callable only from non-atomic contexts,
> > and do whatever's required to ensure that the clock is available. That
> > may end up enabling the clock as a result.
>
> I think that clk_prepare/clk_unprepare looks like the most promising solution,
> so will try to get some preliminary patches done. Here's what I'm planning:
>
> -----
>
> The changes to the API are essentially:
>
> 1) Document clk_enable/clk_disable as callable from atomic contexts, and
> so clock implementations must not sleep within this function.
>
> 2) For clock implementations that may sleep to turn on a clock, we add a
> new pair of functions to the clock API: clk_prepare and clk_unprepare.
>
> These will provide hooks for the clock implmentation to do any sleepable
> work (eg, wait for PLLs to settle) in preparation for a later clk_enable.
>
> For the most common clock implemntation cases (where clocks can be enabled
> atomically), these functions will be a no-op, and all of the enable/disable
> work can be done in clk_enable/clk_disable.
>
> For implementations where clocks require blocking on enable/disable, most
> of the work will be done in clk_prepare/clk_unprepare. The clk_enable
> and clk_disable functions may be no-ops.
>
> For drivers, this means that clk_prepare must be called (and have returned)
> before calling clk_enable.
>
> == Enable/Prepare counts ==
>
> I intend to do the enable and prepare "counting" in the core clock API,
> meaning that that the clk_ops callbacks will only invoked on the first
> prepare/enable and the last unprepare/disable.
>
> == Concurrency ==
>
> Splitting the prepare and enable stages introduces the concurrency
> requirements:
>
> 1) clk_enable must not return before the clock is outputting a valid clock
> signal.
>
> 2) clk_prepare must not return before the clock is fully prepared (ie, it is
> safe to call clk_enable).
>
> It is not possible for clk_enable to wait for the clock to be prepared,
> because that would require synchronisation with clk_prepare, which may then
> require blocking. Therefore:
>
> 3) The clock consumer *must* respect the proper ordering of clk_prepare and
> clk_enable. For example, drivers that call clk_enable during an interrupt
> must ensure that the interrupt handler will not be invoked until
> clk_prepare has returned.
>
> == Other considerations ==
>
> The time that a clock spends "prepared" is a superset of the the time that a
> clock spends "enabled". Therefore, clocks that are switched on during
> clk_prepare (ie, non-atomic clocks) will be running for a larger amount of
> time. In some cases, this can be mitigated by moving some of the final
> (atomic) switching functionality to the clk_enable function.
>
> == Implementation ==
>
> Basically:
>
> struct clk {
> const struct clk_ops *ops
> int enable_count;
> spinlock_t enable_lock;
> int prepare_count;
> struct mutex prepare_lock;
> };
>
> int clk_enable(struct clk *clk)
> {
> int ret = 0;
>
> spin_lock(&clk->enable_lock);
> if (!clk->enable_count)
> ret = clk->ops->enable(clk);
>
> if (!ret)
> clk->enable_count++;
> spin_unlock(&clk->enable_lock);
>
> return ret;
> }
>
> int clk_prepare(struct clk *clk)
> {
> int ret = 0;
>
> mutex_lock(&clk->prepare_lock);
> if (!clk->prepare_count)
> ret = clk->ops->prepare(clk);
>
> if (!ret)
> clk->prepare_count++;
> mutex_unlock(&clk->prepare_lock);
>
> return ret;
> }
>
> -----
>
> Comments welcome, code coming soon.
Do you plan to handle the case that clk_enable is called while prepare
isn't completed (considering the special case "not called at all")?
Maybe BUG_ON(clk->ops->prepare && !clk->prepare_count)?
Alternatively don't force the sleep in clk_prepare (e.g. by protecting
prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
before calling clk->ops->enable?
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
2011/2/1 Uwe Kleine-König <[email protected]>:
.....
> Do you plan to handle the case that clk_enable is called while prepare
> isn't completed (considering the special case "not called at all")?
> Maybe BUG_ON(clk->ops->prepare && !clk->prepare_count)?
Sounds better than the second option.
> Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> before calling clk->ops->enable?
That might result in a driver working on some platforms(those have
atomic clk_prepare)
and not on others(those have sleeping).
Njoi!
On Tue, Feb 01, 2011 at 11:54:49AM +0100, Uwe Kleine-K?nig wrote:
> Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> before calling clk->ops->enable?
That's a completely bad idea. I assume you haven't thought about this
very much.
There's two ways I can think of doing what you're suggesting:
int clk_prepare(struct clk *clk)
{
unsigned long flags;
int ret = 0;
might_sleep();
spin_lock_irqsave(&clk->enable_lock, flags);
if (clk->prepare_count++ == 0)
ret = clk->ops->prepare(clk);
spin_unlock_irqrestore(&clk->enable_clock, flags);
return ret;
}
The problem is that clk->ops->prepare() is called in a non-sleepable
context. So this breaks the whole idea of clk_prepare(), and so isn't
a solution.
The other solution is:
int clk_prepare(struct clk *clk)
{
unsigned long flags;
int ret = 0;
bool first;
might_sleep();
spin_lock_irqsave(clk->enable_lock, flags);
first = clk->prepare_count++ == 0;
spin_unlock_irqrestore(clk->enable_clock, flags);
if (first)
ret = clk->ops->prepare(clk);
return ret;
}
The problem with this is that you now don't have any sane locking on
the prepare callback, and the circumstances under which it's called
are very indefinite. For example, consider a preempt-enabled system:
thread 1 thread 2 prepare_count
clk_prepare 0
clk->prepare_count++ 1
<thread switch>
clk_prepare 1
clk->prepare_count++ 2
clk_prepare returns 2
clk_enable 2
<explodes as clock is not prepared>
<thread switch>
clk->ops->prepare(clk)
So really, what you're suggesting is completely broken.
On Tue, Feb 01, 2011 at 10:05:56PM +0900, Jassi Brar wrote:
> 2011/2/1 Uwe Kleine-K?nig <[email protected]>:
>
> .....
>
> > Do you plan to handle the case that clk_enable is called while prepare
> > isn't completed (considering the special case "not called at all")?
> > Maybe BUG_ON(clk->ops->prepare && !clk->prepare_count)?
> Sounds better than the second option.
>
> > Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> > prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> > before calling clk->ops->enable?
> That might result in a driver working on some platforms(those have
> atomic clk_prepare)
> and not on others(those have sleeping).
The first option has the same result. E.g. on some platforms
clk->ops->prepare might be NULL, on others it's not.
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Tue, Feb 01, 2011 at 01:15:12PM +0000, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 11:54:49AM +0100, Uwe Kleine-K?nig wrote:
> > Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> > prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> > before calling clk->ops->enable?
>
> That's a completely bad idea. I assume you haven't thought about this
> very much.
Right, but I thought it a bit further than you did. Like the following:
int clk_prepare(struct clk *clk)
{
int ret = 0, first;
unsigned long flags;
spin_lock_irqsave(&clk->enable_lock, flags);
if (clk->flags & CLK_BUSY) {
/*
* this must not happen, please serialize calls to
* clk_prepare/clk_enable
*/
ret = -EBUSY;
goto out_unlock;
}
first = clk->prepare_count++ == 0;
if (first)
clk->flags |= CLK_BUSY;
spin_unlock_irqrestore(&clk->enable_lock, flags);
if (!first)
return 0;
if (clk->ops->prepare) {
might_sleep();
ret = clk->ops->prepare(clk);
}
spin_lock_irqsave(&clk->enable_lock, flags);
clk->flags &= ~CLK_BUSY;
if (ret)
clk->prepare_count--;
out_unlock:
spin_unlock_irqrestore(&clk->enable_lock, flags);
return ret;
}
If you now find a problem with that you can blame me not having thought
it to an end.
And note, this is only a suggestion. I.e. I don't know what is the best
to do in the case where I implemented returning -EBUSY above. BUG?
Wait for CLK_BUSY to be cleared?
I'm not sure I like "clk_prepare sleeps iff unprepared but preparable".
Still I think the approach is worth to be discussed.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Tue, Feb 01, 2011 at 03:18:37PM +0100, Uwe Kleine-K?nig wrote:
> On Tue, Feb 01, 2011 at 01:15:12PM +0000, Russell King - ARM Linux wrote:
> > On Tue, Feb 01, 2011 at 11:54:49AM +0100, Uwe Kleine-K?nig wrote:
> > > Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> > > prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> > > before calling clk->ops->enable?
> >
> > That's a completely bad idea. I assume you haven't thought about this
> > very much.
> Right, but I thought it a bit further than you did. Like the following:
>
> int clk_prepare(struct clk *clk)
> {
> int ret = 0, first;
> unsigned long flags;
>
> spin_lock_irqsave(&clk->enable_lock, flags);
> if (clk->flags & CLK_BUSY) {
> /*
> * this must not happen, please serialize calls to
> * clk_prepare/clk_enable
> */
How do different drivers serialize calls to clk_prepare? Are you
really suggesting that we should have a global mutex somewhere to
prevent this?
> ret = -EBUSY;
> goto out_unlock;
> }
> first = clk->prepare_count++ == 0;
> if (first)
> clk->flags |= CLK_BUSY;
> spin_unlock_irqrestore(&clk->enable_lock, flags);
>
> if (!first)
> return 0;
>
> if (clk->ops->prepare) {
> might_sleep();
> ret = clk->ops->prepare(clk);
> }
>
> spin_lock_irqsave(&clk->enable_lock, flags);
> clk->flags &= ~CLK_BUSY;
> if (ret)
> clk->prepare_count--;
> out_unlock:
> spin_unlock_irqrestore(&clk->enable_lock, flags);
>
> return ret;
> }
>
> If you now find a problem with that you can blame me not having thought
> it to an end.
>
> And note, this is only a suggestion. I.e. I don't know what is the best
> to do in the case where I implemented returning -EBUSY above. BUG?
> Wait for CLK_BUSY to be cleared?
So what're you proposing that a driver writer should do when he sees
-EBUSY returned from this function? Abandon the probe() returning -EBUSY
and hope the user retries later? Or maybe:
do {
err = clk_prepare(clk);
} while (err == -EBUSY);
?
I don't think that's reasonable to offload this onto driver writers, who
already have a big enough problem already. The less complexity that
driver writers have to deal with, the better.
Hi Uwe,
Thanks for the feedback, I'm not sure I like the more complex approach though:
> Right, but I thought it a bit further than you did. Like the following:
>
> int clk_prepare(struct clk *clk)
> {
> int ret = 0, first;
> unsigned long flags;
>
> spin_lock_irqsave(&clk->enable_lock, flags);
> if (clk->flags & CLK_BUSY) {
> /*
> * this must not happen, please serialize calls to
> * clk_prepare/clk_enable
> */
> ret = -EBUSY;
> goto out_unlock;
Why is this an error? Two separate drivers may be clk_prepare()-ing at the
same time, which should be acceptable. Both calls should block until the
prepare is complete.
> }
> first = clk->prepare_count++ == 0;
> if (first)
> clk->flags |= CLK_BUSY;
> spin_unlock_irqrestore(&clk->enable_lock, flags);
>
> if (!first)
> return 0;
>
> if (clk->ops->prepare) {
> might_sleep();
> ret = clk->ops->prepare(clk);
> }
>
> spin_lock_irqsave(&clk->enable_lock, flags);
> clk->flags &= ~CLK_BUSY;
> if (ret)
> clk->prepare_count--;
> out_unlock:
> spin_unlock_irqrestore(&clk->enable_lock, flags);
>
> return ret;
> }
Cheers,
Jeremy
On Tue, Feb 01, 2011 at 03:00:24PM +0100, Uwe Kleine-K?nig wrote:
> On Tue, Feb 01, 2011 at 10:05:56PM +0900, Jassi Brar wrote:
> > 2011/2/1 Uwe Kleine-K?nig <[email protected]>:
> >
> > .....
> >
> > > Do you plan to handle the case that clk_enable is called while prepare
> > > isn't completed (considering the special case "not called at all")?
> > > Maybe BUG_ON(clk->ops->prepare && !clk->prepare_count)?
> > Sounds better than the second option.
> >
> > > Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> > > prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> > > before calling clk->ops->enable?
> > That might result in a driver working on some platforms(those have
> > atomic clk_prepare)
> > and not on others(those have sleeping).
> The first option has the same result. E.g. on some platforms
> clk->ops->prepare might be NULL, on others it's not.
If clk->ops->prepare is NULL, then clk_prepare() better return success
as it should mean "no preparation necessary", not "someone didn't
implement it so its an error".
Calling clk->ops->enable() with a spinlock held will ensure that no one
tries to make that method sleep, so if people want sleeping stuff they
have to use the clk_prepare() stuff. It's a self-enforcing API which
ensures that we don't get sleeping stuff inside clk_enable().
And with a check in clk_enable() for a preparation, it helps to ensure
that drivers do call clk_prepare() before clk_enable() - though it can't
guarantee it in every case.
On Tue, Feb 01, 2011 at 02:39:32PM +0000, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 03:18:37PM +0100, Uwe Kleine-K?nig wrote:
> > On Tue, Feb 01, 2011 at 01:15:12PM +0000, Russell King - ARM Linux wrote:
> > > On Tue, Feb 01, 2011 at 11:54:49AM +0100, Uwe Kleine-K?nig wrote:
> > > > Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> > > > prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> > > > before calling clk->ops->enable?
> > >
> > > That's a completely bad idea. I assume you haven't thought about this
> > > very much.
> > Right, but I thought it a bit further than you did. Like the following:
> >
> > int clk_prepare(struct clk *clk)
> > {
> > int ret = 0, first;
> > unsigned long flags;
> >
> > spin_lock_irqsave(&clk->enable_lock, flags);
> > if (clk->flags & CLK_BUSY) {
> > /*
> > * this must not happen, please serialize calls to
> > * clk_prepare/clk_enable
> > */
>
> How do different drivers serialize calls to clk_prepare? Are you
> really suggesting that we should have a global mutex somewhere to
> prevent this?
yeah, didn't thought about multiple consumers, so (as Jeremy suggested)
the right thing is to sleep until CLK_BUSY is cleared.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Tue, Feb 01, 2011 at 03:14:18PM +0000, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 03:00:24PM +0100, Uwe Kleine-K?nig wrote:
> > On Tue, Feb 01, 2011 at 10:05:56PM +0900, Jassi Brar wrote:
> > > 2011/2/1 Uwe Kleine-K?nig <[email protected]>:
> > >
> > > .....
> > >
> > > > Do you plan to handle the case that clk_enable is called while prepare
> > > > isn't completed (considering the special case "not called at all")?
> > > > Maybe BUG_ON(clk->ops->prepare && !clk->prepare_count)?
> > > Sounds better than the second option.
> > >
> > > > Alternatively don't force the sleep in clk_prepare (e.g. by protecting
> > > > prepare_count by a spinlock (probably enable_lock)) and call clk_prepare
> > > > before calling clk->ops->enable?
> > > That might result in a driver working on some platforms(those have
> > > atomic clk_prepare)
> > > and not on others(those have sleeping).
> > The first option has the same result. E.g. on some platforms
> > clk->ops->prepare might be NULL, on others it's not.
>
> If clk->ops->prepare is NULL, then clk_prepare() better return success
> as it should mean "no preparation necessary", not "someone didn't
> implement it so its an error".
>
> Calling clk->ops->enable() with a spinlock held will ensure that no one
> tries to make that method sleep, so if people want sleeping stuff they
> have to use the clk_prepare() stuff. It's a self-enforcing API which
> ensures that we don't get sleeping stuff inside clk_enable().
>
> And with a check in clk_enable() for a preparation, it helps to ensure
> that drivers do call clk_prepare() before clk_enable() - though it can't
> guarantee it in every case.
Full ack. (I wonder if you misunderstood me or wanted to put my
statement into more words. Jassi didn't like that a clk_enable without
a previous clk_prepare worked on some platforms and on others it
doesn't. With BUG_ON(clk->ops->prepare && !clk->prepare_count) in
clk_enable we have exactly this situation.)
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Tue, Feb 01, 2011 at 04:18:46PM +0100, Uwe Kleine-K?nig wrote:
> yeah, didn't thought about multiple consumers, so (as Jeremy suggested)
> the right thing is to sleep until CLK_BUSY is cleared.
A simpler way to write this is:
int clk_prepare(struct clk *clk)
{
int ret = 0;
mutex_lock(&clk->mutex);
if (clk->prepared == 0)
ret = clk->ops->prepare(clk);
if (ret == 0)
clk->prepared++;
mutex_unlock(&clk->mutex);
return ret;
}
I think we want to take a common mutex not only for clk_prepare(), but
also for clk_set_rate(). If prepare() is waiting for a PLL to lock,
we don't want a set_rate() interfering with that.
I'd also be tempted at this stage to build-in a no-op dummy clock,
that being the NULL clk:
int clk_prepare(struct clk *clk)
{
int ret = 0;
if (clk) {
mutex_lock(&clk->mutex);
if (clk->prepared == 0)
ret = clk->ops->prepare(clk);
if (ret == 0)
clk->prepared++;
mutex_unlock(&clk->mutex);
}
return ret;
}
as we have various platforms defining a dummy struct clk as a way of
satisfying various driver requirements. These dummy clocks are exactly
that - they're complete no-ops.
On Tue, Feb 01, 2011 at 04:22:03PM +0100, Uwe Kleine-K?nig wrote:
> Full ack. (I wonder if you misunderstood me or wanted to put my
> statement into more words. Jassi didn't like that a clk_enable without
> a previous clk_prepare worked on some platforms and on others it
> doesn't. With BUG_ON(clk->ops->prepare && !clk->prepare_count) in
> clk_enable we have exactly this situation.)
Even with a NULL clk->ops->prepare function, we still want drivers to
have called clk_prepare(). So we can do something like:
if (WARN_ON(clk->prepare_count == 0))
return -EINVAL;
in clk_enable() should be sufficient and noisy enough not to be missed.
I'd avoid BUG_ON() here as that will take the system down, which may
increase the chances of getting useful bug reports.
On Tue, Feb 01, 2011 at 03:24:58PM +0000, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 04:18:46PM +0100, Uwe Kleine-K?nig wrote:
> > yeah, didn't thought about multiple consumers, so (as Jeremy suggested)
> > the right thing is to sleep until CLK_BUSY is cleared.
>
> A simpler way to write this is:
>
> int clk_prepare(struct clk *clk)
> {
> int ret = 0;
>
> mutex_lock(&clk->mutex);
> if (clk->prepared == 0)
> ret = clk->ops->prepare(clk);
> if (ret == 0)
> clk->prepared++;
> mutex_unlock(&clk->mutex);
>
> return ret;
> }
But you cannot call this in atomic context when you know the clock is
already prepared.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Tue, Feb 01, 2011 at 04:53:44PM +0100, Uwe Kleine-K?nig wrote:
> On Tue, Feb 01, 2011 at 03:24:58PM +0000, Russell King - ARM Linux wrote:
> > On Tue, Feb 01, 2011 at 04:18:46PM +0100, Uwe Kleine-K?nig wrote:
> > > yeah, didn't thought about multiple consumers, so (as Jeremy suggested)
> > > the right thing is to sleep until CLK_BUSY is cleared.
> >
> > A simpler way to write this is:
> >
> > int clk_prepare(struct clk *clk)
> > {
> > int ret = 0;
> >
> > mutex_lock(&clk->mutex);
> > if (clk->prepared == 0)
> > ret = clk->ops->prepare(clk);
> > if (ret == 0)
> > clk->prepared++;
> > mutex_unlock(&clk->mutex);
> >
> > return ret;
> > }
> But you cannot call this in atomic context when you know the clock is
> already prepared.
So? You're not _supposed_ to call it from any atomic context ever.
On Tue, Feb 01, 2011 at 05:06:37PM +0000, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 04:53:44PM +0100, Uwe Kleine-K?nig wrote:
> > On Tue, Feb 01, 2011 at 03:24:58PM +0000, Russell King - ARM Linux wrote:
> > > On Tue, Feb 01, 2011 at 04:18:46PM +0100, Uwe Kleine-K?nig wrote:
> > > > yeah, didn't thought about multiple consumers, so (as Jeremy suggested)
> > > > the right thing is to sleep until CLK_BUSY is cleared.
> > >
> > > A simpler way to write this is:
> > >
> > > int clk_prepare(struct clk *clk)
> > > {
> > > int ret = 0;
> > >
> > > mutex_lock(&clk->mutex);
> > > if (clk->prepared == 0)
> > > ret = clk->ops->prepare(clk);
> > > if (ret == 0)
> > > clk->prepared++;
> > > mutex_unlock(&clk->mutex);
> > >
> > > return ret;
> > > }
> > But you cannot call this in atomic context when you know the clock is
> > already prepared.
>
> So? You're not _supposed_ to call it from any atomic context ever.
My motivation for a more complicated clk_prepare was to make clk_prepare
atomic when that's possible (i.e. when the clk is already prepared) and
call it before the enable callback in clk_enable. Then everything
behaves nicely even if clk_enable is called from atomic context provided
that the clock was prepared before (or doesn't need to).
If a driver writer doesn't know that a certain clock might need to sleep
at some point he runs into an atomic might_sleep with your approach and
with mine.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Tue, Feb 01, 2011 at 08:32:01PM +0100, Uwe Kleine-K?nig wrote:
> On Tue, Feb 01, 2011 at 05:06:37PM +0000, Russell King - ARM Linux wrote:
> > So? You're not _supposed_ to call it from any atomic context ever.
>
> My motivation for a more complicated clk_prepare was to make clk_prepare
> atomic when that's possible (i.e. when the clk is already prepared) and
> call it before the enable callback in clk_enable. Then everything
> behaves nicely even if clk_enable is called from atomic context provided
> that the clock was prepared before (or doesn't need to).
You really don't get the point of clk_prepare() do you. I'm not
going to bother trying to educate you anymore.
Hopefully someone with more patience can give you the necessary
teaching to make you understand.
On Tue, 1 Feb 2011, Uwe Kleine-K?nig wrote:
> My motivation for a more complicated clk_prepare was to make clk_prepare
> atomic when that's possible (i.e. when the clk is already prepared) and
> call it before the enable callback in clk_enable. Then everything
> behaves nicely even if clk_enable is called from atomic context provided
> that the clock was prepared before (or doesn't need to).
NOOOOOOOOO!!!
We _do_ want drivers to _always_ call clk_prepare() in sleepable
context, and _then_ always call clk_enable() in whatever context they
wish. Period.
Nicolas
On 02/01/2011 11:56 AM, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 08:32:01PM +0100, Uwe Kleine-K?nig wrote:
>> On Tue, Feb 01, 2011 at 05:06:37PM +0000, Russell King - ARM Linux wrote:
>>> So? You're not _supposed_ to call it from any atomic context ever.
>>
>> My motivation for a more complicated clk_prepare was to make clk_prepare
>> atomic when that's possible (i.e. when the clk is already prepared) and
>> call it before the enable callback in clk_enable. Then everything
>> behaves nicely even if clk_enable is called from atomic context provided
>> that the clock was prepared before (or doesn't need to).
>
> You really don't get the point of clk_prepare() do you. I'm not
> going to bother trying to educate you anymore.
>
> Hopefully someone with more patience can give you the necessary
> teaching to make you understand.
Uwe,
If the driver is calling clk_prepare() right next to clk_enable()
knowing it's been already prepared and will hence be "atomic" (this is
actually not true), then by your description, it's pointless to call
clk_prepare().
If you want the driver to call clk_prepare() in atomic context because
it will be atomic in most cases -- well, that's wrong. It's either
atomic or is NOT atomic. There is no in between. If a call is NOT
atomic, it can't be called in atomic context. Long story short, if you
expect clk_prepare() to be atomic under any circumstance, it beats the
point of introducing clk_prepare().
Hope I helped.
-Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On 02/01/2011 07:24 AM, Russell King - ARM Linux wrote:
> A simpler way to write this is:
>
> int clk_prepare(struct clk *clk)
> {
> int ret = 0;
>
> mutex_lock(&clk->mutex);
> if (clk->prepared == 0)
> ret = clk->ops->prepare(clk);
> if (ret == 0)
> clk->prepared++;
> mutex_unlock(&clk->mutex);
>
> return ret;
> }
>
> I think we want to take a common mutex not only for clk_prepare(), but
> also for clk_set_rate(). If prepare() is waiting for a PLL to lock,
> we don't want a set_rate() interfering with that.
Looks like this is the best acknowledgment/response I can expect to get
from Russell on this point that I raised.
Jeremy,
When you update the comments/doc to indicate clk_prepare/unprepare is
not atomic, can you also update the comment for set_rate() and mark it
as non-atomic?
Thanks for starting this thread. My efforts to reignite the other thread
didn't go anywhere. Glad to see it's moving forward.
> I'd also be tempted at this stage to build-in a no-op dummy clock,
> that being the NULL clk:
>[snip]
> as we have various platforms defining a dummy struct clk as a way of
> satisfying various driver requirements. These dummy clocks are exactly
> that - they're complete no-ops.
Unrelated to this thread, but I Ack this request too.
-Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Tue, Feb 01, 2011 at 12:33:12PM -0800, Saravana Kannan wrote:
> Looks like this is the best acknowledgment/response I can expect to get
> from Russell on this point that I raised.
Sorry, I've been up to my eyeballs with other stuff over the last few
weeks. Yes, I think clk_set_rate() needs to be sleep-able too.
Hello,
On Tue, Feb 01, 2011 at 12:21:45PM -0800, Saravana Kannan wrote:
> If the driver is calling clk_prepare() right next to clk_enable()
> knowing it's been already prepared and will hence be "atomic" (this
> is actually not true), then by your description, it's pointless to
> call clk_prepare().
Well not completely, as it increases the reference count. The advantage
would be that clk_enable counts addionally as prepare, so it would be
impossible to unprepare an enabled clock. And the other way round an
unprepared clock would never be enabled.
> If you want the driver to call clk_prepare() in atomic context
> because it will be atomic in most cases -- well, that's wrong. It's
> either atomic or is NOT atomic. There is no in between. If a call is
> NOT atomic, it can't be called in atomic context. Long story short,
> if you expect clk_prepare() to be atomic under any circumstance, it
> beats the point of introducing clk_prepare().
Well, with my suggestion it's atomic when certain precondions are given.
IMHO that's better than "atomic in most cases" because the caller can
assert that everything goes smooth.
These preconditions are asserted when the driver writer is careful
enough to stick to the API.
Either my idea is bad or I'm unable to sell it appropriately. Be it as
it is, I will stop to make a case for it.
Best regards and thanks for your try,
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On 02/01/2011 07:28 AM, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 04:22:03PM +0100, Uwe Kleine-K?nig wrote:
>> Full ack. (I wonder if you misunderstood me or wanted to put my
>> statement into more words. Jassi didn't like that a clk_enable without
>> a previous clk_prepare worked on some platforms and on others it
>> doesn't. With BUG_ON(clk->ops->prepare&& !clk->prepare_count) in
>> clk_enable we have exactly this situation.)
>
> Even with a NULL clk->ops->prepare function, we still want drivers to
> have called clk_prepare(). So we can do something like:
>
> if (WARN_ON(clk->prepare_count == 0))
> return -EINVAL;
>
> in clk_enable() should be sufficient and noisy enough not to be missed.
This code will only catch the error when it actually happens and will
even miss catching some of them (if timed right -- unprepare happens in
the other core after this check is executed).
I really wish there was something better we could do to help driver devs
catch errors of calling enable without calling prepare(). Some thing
like spin lock debug, or the might_sleeps() inside mutexes, etc.
Hmm... Jeremy, how about doing a similar check in the unprepare code?
You could WARN/BUG ON the prepare count going to zero when the enable
count is still non-zero?
Thanks,
Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On 02/01/2011 07:24 AM, Russell King - ARM Linux wrote:
>
> I'd also be tempted at this stage to build-in a no-op dummy clock,
> that being the NULL clk:
>
> int clk_prepare(struct clk *clk)
> {
> int ret = 0;
>
> if (clk) {
> mutex_lock(&clk->mutex);
> if (clk->prepared == 0)
> ret = clk->ops->prepare(clk);
> if (ret == 0)
> clk->prepared++;
> mutex_unlock(&clk->mutex);
> }
>
> return ret;
> }
I'm afraid this will hide enable/disable imbalances on some targets and
then expose them on others. Maybe its not a big problem though since
this also elegantly handles the root(s) of the tree.
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Tue, Feb 01, 2011 at 12:59:11PM -0800, Stephen Boyd wrote:
> On 02/01/2011 07:24 AM, Russell King - ARM Linux wrote:
> > I'd also be tempted at this stage to build-in a no-op dummy clock,
> > that being the NULL clk:
> >
> > int clk_prepare(struct clk *clk)
> > {
> > int ret = 0;
> >
> > if (clk) {
> > mutex_lock(&clk->mutex);
> > if (clk->prepared == 0)
> > ret = clk->ops->prepare(clk);
> > if (ret == 0)
> > clk->prepared++;
> > mutex_unlock(&clk->mutex);
> > }
> >
> > return ret;
> > }
>
> I'm afraid this will hide enable/disable imbalances on some targets and
> then expose them on others. Maybe its not a big problem though since
> this also elegantly handles the root(s) of the tree.
You can't catch enable/disable imbalances in the prepare code, and you
can't really catch them in the unprepare code either.
Consider two drivers sharing the same struct clk. When the second driver
prepares the clock, the enable count could well be non-zero, caused by
the first driver. Ditto for when the second driver is removed, and it
calls unprepare - the enable count may well be non-zero.
The only thing you can check is that when the prepare count is zero,
the enable count is also zero. You can also check in clk_enable() and
clk_disable() that the prepare count is non-zero.
If you want tigher checking than that, you need to somehow identify and
match up the clk_prepare/clk_enable/clk_disable/clk_unprepare calls from
a particular driver instance. Addresses of the functions don't work as
you can't be certain that driver code will be co-located within a certain
range. Adding an additional argument to these functions which is driver
instance specific seems to be horrible too.
2011/2/2 Russell King - ARM Linux <[email protected]>:
> On Tue, Feb 01, 2011 at 04:22:03PM +0100, Uwe Kleine-König wrote:
>> Full ack. (I wonder if you misunderstood me or wanted to put my
>> statement into more words. Jassi didn't like that a clk_enable without
>> a previous clk_prepare worked on some platforms and on others it
>> doesn't. With BUG_ON(clk->ops->prepare && !clk->prepare_count) in
>> clk_enable we have exactly this situation.)
>
> Even with a NULL clk->ops->prepare function, we still want drivers to
> have called clk_prepare(). So we can do something like:
>
> if (WARN_ON(clk->prepare_count == 0))
> return -EINVAL;
>
> in clk_enable() should be sufficient and noisy enough not to be missed.
>
> I'd avoid BUG_ON() here as that will take the system down, which may
> increase the chances of getting useful bug reports.
Having thought about it, I think it's not necessary to immediately catch
drivers that work on some platforms and not on others -- a mere comment
'please add clk_prepare' during code review or a patch adding 'clk_prepare'
later upon stumbling across a platform on which the driver doesn't work,
should be OK. Let us not fret about it.
That leaves us with only having to ensure that :-
a) No two calls to clk_prepare/unprepare _hooks_ are consecutive.
b) clk_prepare is done on the clock (not necessarily by the driver
under consideration) before calls to clk_enable.
I think (a) is already easily managed by having the prepare_count,
and (b) can be reasonably managed by what Russell suggests above.
So, FWIW, I am for the idea.
Njoi!
On Tue, Feb 01, 2011 at 09:43:31PM +0100, Uwe Kleine-K?nig wrote:
> Hello,
>
> On Tue, Feb 01, 2011 at 12:21:45PM -0800, Saravana Kannan wrote:
> > If the driver is calling clk_prepare() right next to clk_enable()
> > knowing it's been already prepared and will hence be "atomic" (this
> > is actually not true), then by your description, it's pointless to
> > call clk_prepare().
> Well not completely, as it increases the reference count. The advantage
> would be that clk_enable counts addionally as prepare, so it would be
> impossible to unprepare an enabled clock. And the other way round an
> unprepared clock would never be enabled.
>
> > If you want the driver to call clk_prepare() in atomic context
> > because it will be atomic in most cases -- well, that's wrong. It's
> > either atomic or is NOT atomic. There is no in between. If a call is
> > NOT atomic, it can't be called in atomic context. Long story short,
> > if you expect clk_prepare() to be atomic under any circumstance, it
> > beats the point of introducing clk_prepare().
> Well, with my suggestion it's atomic when certain precondions are given.
> IMHO that's better than "atomic in most cases" because the caller can
> assert that everything goes smooth.
> These preconditions are asserted when the driver writer is careful
> enough to stick to the API.
IMHO, clk_prepare is always called in non-atomic context, so it doesn't matter
whether it's really atomic or not. We don't have to make it as atomic as
possible.
Thanks
Richard
>
> Either my idea is bad or I'm unable to sell it appropriately. Be it as
> it is, I will stop to make a case for it.
>
> Best regards and thanks for your try,
> Uwe
>
> --
> Pengutronix e.K. | Uwe Kleine-K?nig |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Tue, Feb 01, 2011 at 09:24:09PM +0000, Russell King - ARM Linux wrote:
> On Tue, Feb 01, 2011 at 12:59:11PM -0800, Stephen Boyd wrote:
> > On 02/01/2011 07:24 AM, Russell King - ARM Linux wrote:
> > > I'd also be tempted at this stage to build-in a no-op dummy clock,
> > > that being the NULL clk:
> > >
> > > int clk_prepare(struct clk *clk)
> > > {
> > > int ret = 0;
> > >
> > > if (clk) {
> > > mutex_lock(&clk->mutex);
> > > if (clk->prepared == 0)
> > > ret = clk->ops->prepare(clk);
> > > if (ret == 0)
> > > clk->prepared++;
> > > mutex_unlock(&clk->mutex);
> > > }
> > >
> > > return ret;
> > > }
> >
> > I'm afraid this will hide enable/disable imbalances on some targets and
> > then expose them on others. Maybe its not a big problem though since
> > this also elegantly handles the root(s) of the tree.
>
> You can't catch enable/disable imbalances in the prepare code, and you
> can't really catch them in the unprepare code either.
>
> Consider two drivers sharing the same struct clk. When the second driver
> prepares the clock, the enable count could well be non-zero, caused by
> the first driver. Ditto for when the second driver is removed, and it
> calls unprepare - the enable count may well be non-zero.
>
> The only thing you can check is that when the prepare count is zero,
> the enable count is also zero. You can also check in clk_enable() and
> clk_disable() that the prepare count is non-zero.
but how can we check prepare count without mutex lock? Even if prepare count
is atomic_t, it can not guarantee the clock is actually prepared or unprepared.
So it's important for driver writer to maintain the call sequence.
Thanks
Richard
>
> If you want tigher checking than that, you need to somehow identify and
> match up the clk_prepare/clk_enable/clk_disable/clk_unprepare calls from
> a particular driver instance. Addresses of the functions don't work as
> you can't be certain that driver code will be co-located within a certain
> range. Adding an additional argument to these functions which is driver
> instance specific seems to be horrible too.
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Hello Richard,
On Fri, Feb 04, 2011 at 05:54:24PM +0800, Richard Zhao wrote:
> On Tue, Feb 01, 2011 at 09:24:09PM +0000, Russell King - ARM Linux wrote:
> > On Tue, Feb 01, 2011 at 12:59:11PM -0800, Stephen Boyd wrote:
> > > On 02/01/2011 07:24 AM, Russell King - ARM Linux wrote:
> > > > I'd also be tempted at this stage to build-in a no-op dummy clock,
> > > > that being the NULL clk:
> > > >
> > > > int clk_prepare(struct clk *clk)
> > > > {
> > > > int ret = 0;
> > > >
> > > > if (clk) {
> > > > mutex_lock(&clk->mutex);
> > > > if (clk->prepared == 0)
> > > > ret = clk->ops->prepare(clk);
> > > > if (ret == 0)
> > > > clk->prepared++;
> > > > mutex_unlock(&clk->mutex);
> > > > }
> > > >
> > > > return ret;
> > > > }
> > >
> > > I'm afraid this will hide enable/disable imbalances on some targets and
> > > then expose them on others. Maybe its not a big problem though since
> > > this also elegantly handles the root(s) of the tree.
> >
> > You can't catch enable/disable imbalances in the prepare code, and you
> > can't really catch them in the unprepare code either.
> >
> > Consider two drivers sharing the same struct clk. When the second driver
> > prepares the clock, the enable count could well be non-zero, caused by
> > the first driver. Ditto for when the second driver is removed, and it
> > calls unprepare - the enable count may well be non-zero.
> >
> > The only thing you can check is that when the prepare count is zero,
> > the enable count is also zero. You can also check in clk_enable() and
> > clk_disable() that the prepare count is non-zero.
> but how can we check prepare count without mutex lock? Even if prepare count
> is atomic_t, it can not guarantee the clock is actually prepared or unprepared.
> So it's important for driver writer to maintain the call sequence.
I happily point out that the prepare_count needs to be protected by a
spinlock and you need a flag that signals a prepare or unprepare is
currently running.
SCNR
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Fri, Feb 04, 2011 at 05:54:24PM +0800, Richard Zhao wrote:
> On Tue, Feb 01, 2011 at 09:24:09PM +0000, Russell King - ARM Linux wrote:
> > You can't catch enable/disable imbalances in the prepare code, and you
> > can't really catch them in the unprepare code either.
> >
> > Consider two drivers sharing the same struct clk. When the second driver
> > prepares the clock, the enable count could well be non-zero, caused by
> > the first driver. Ditto for when the second driver is removed, and it
> > calls unprepare - the enable count may well be non-zero.
> >
> > The only thing you can check is that when the prepare count is zero,
> > the enable count is also zero. You can also check in clk_enable() and
> > clk_disable() that the prepare count is non-zero.
>
> but how can we check prepare count without mutex lock? Even if prepare count
> is atomic_t, it can not guarantee the clock is actually prepared or unprepared.
> So it's important for driver writer to maintain the call sequence.
Forget atomic_t - it's the most abused type in the kernel. Just because
something says its atomic doesn't make it so. In a use like this,
atomic_t just buys you additional needless complexity with no benefit.
Of course we can check the prepared count. What we can't do is check
that it doesn't change concurrently - but that's something we can't do
anyway.
int clk_enable(struct clk *clk)
{
unsigned long flags;
int ret = 0;
if (clk) {
if (WARN_ON(!clk->prepare_count))
return -EINVAL;
spin_lock_irqsave(&clk->lock, flags);
if (clk->enable_count++ == 0)
ret = clk->ops->enable(clk);
spin_unlock_irqrestore(&clk->lock, flags);
}
return ret;
}
is entirely sufficient to catch the case of a single-use clock not being
prepared before clk_enable() is called.
We're after detecting drivers missing calls to clk_prepare(), we're not
after detecting concurrent calls to clk_prepare()/clk_unprepare().
On Fri, Feb 04, 2011 at 11:21:20AM +0100, Uwe Kleine-K?nig wrote:
> I happily point out that the prepare_count needs to be protected by a
> spinlock and you need a flag that signals a prepare or unprepare is
> currently running.
It's really simple. You don't use a struct clk pointer in any way until
you've called a clk_get() to get a pointer. So what's the problem with
ensuring that you do clk_prepare() on it before you register whatever
services may end up calling clk_enable().
That is good practice. It's precisely the same practice which says that
you shall not register device drivers with subsystems, thereby making
them visible, until you're absolutely ready in the driver to start taking
requests to use your driver. Precisely the same thing applies here.
In other words, to go back to the UART console driver case, in the
UART console setup function, you do this:
clk = clk_get(...);
if (IS_ERR(clk))
return PTR_ERR(clk);
err = clk_prepare(clk);
if (err) {
clk_put(clk);
return err;
}
rate = clk_get_rate(clk);
... setup UART, setup baud rate according to rate ...
return 0;
So, this means that clk_enable() in the console write function will not
be called until after the initialization function has finished - by which
time clk_prepare() will have completed.
There is no need for any kind of spinlocking, atomic types or other such
crap for the prepare count. We do not care about concurrent clk_enables().
The only time you'd need such games as you're suggesting is if you're still
promoting your idea about calling clk_prepare() from clk_enable() "in case
driver writers forget it", which is soo broken it's untrue.
On Fri, Feb 4, 2011 at 7:48 PM, Russell King - ARM Linux
<[email protected]> wrote:
> int clk_enable(struct clk *clk)
> {
> unsigned long flags;
> int ret = 0;
>
> if (clk) {
> if (WARN_ON(!clk->prepare_count))
> return -EINVAL;
>
> spin_lock_irqsave(&clk->lock, flags);
> if (clk->enable_count++ == 0)
> ret = clk->ops->enable(clk);
> spin_unlock_irqrestore(&clk->lock, flags);
> }
> return ret;
> }
>
> is entirely sufficient to catch the case of a single-use clock not being
> prepared before clk_enable() is called.
>
> We're after detecting drivers missing calls to clk_prepare(), we're not
> after detecting concurrent calls to clk_prepare()/clk_unprepare().
I hope you mean 'making sure the clock is prepared before it's enabled
' rather than
'catching a driver that doesn't do clk_prepare before clk_enable'.
Because, the above implementation still doesn't catch a driver that
doesn't call clk_prepare
but simply uses a clock that happens to have been already prepare'd by
some other
driver or the platform.
On Fri, Feb 04, 2011 at 08:04:03PM +0900, Jassi Brar wrote:
> On Fri, Feb 4, 2011 at 7:48 PM, Russell King - ARM Linux
> <[email protected]> wrote:
>
> > int clk_enable(struct clk *clk)
> > {
> > ? ? ? ?unsigned long flags;
> > ? ? ? ?int ret = 0;
> >
> > ? ? ? ?if (clk) {
> > ? ? ? ? ? ? ? ?if (WARN_ON(!clk->prepare_count))
> > ? ? ? ? ? ? ? ? ? ? ? ?return -EINVAL;
> >
> > ? ? ? ? ? ? ? ?spin_lock_irqsave(&clk->lock, flags);
> > ? ? ? ? ? ? ? ?if (clk->enable_count++ == 0)
> > ? ? ? ? ? ? ? ? ? ? ? ?ret = clk->ops->enable(clk);
> > ? ? ? ? ? ? ? ?spin_unlock_irqrestore(&clk->lock, flags);
> > ? ? ? ?}
> > ? ? ? ?return ret;
> > }
> >
> > is entirely sufficient to catch the case of a single-use clock not being
> > prepared before clk_enable() is called.
> >
> > We're after detecting drivers missing calls to clk_prepare(), we're not
> > after detecting concurrent calls to clk_prepare()/clk_unprepare().
>
> I hope you mean 'making sure the clock is prepared before it's enabled
> ' rather than
> 'catching a driver that doesn't do clk_prepare before clk_enable'.
> Because, the above implementation still doesn't catch a driver that
> doesn't call clk_prepare
> but simply uses a clock that happens to have been already prepare'd by
> some other
> driver or the platform.
No, I mean what I said.
The only way to do what you're asking is to attach a list of identifiers
which have prepared a clock to the struct clk, where each identifier is
unique to each driver instance.
So what that becomes is:
struct prepared_instance {
struct list_head node;
void *driver_id;
};
int clk_prepare(struct clk *clk, void *driver_id)
{
struct prepared_instance *inst;
int ret = 0;
if (clk) {
inst = kmalloc(sizeof(*inst), GFP_KERNEL);
if (!inst)
return -ENOMEM;
inst->driver_id = driver_id;
mutex_lock(&clk->mutex);
if (clk->prepare_count++ == 0)
ret = clk->ops->prepare(clk);
if (ret == 0) {
spin_lock_irqsave(&clk->lock, flags);
list_add(&inst->node, &clk->prepare_list);
spin_unlock_irqrestore(&clk->lock, flags);
} else
clk->prepare_count--;
mutex_unlock(&clk->mutex);
}
return ret;
}
int clk_enable(struct clk *clk, void *driver_id)
{
unsigned long flags;
int ret = 0;
if (clk) {
struct prepare_instance *inst;
spin_lock_irqsave(&clk->lock, flags);
list_for_each_entry(inst, &clk->prepare_list, node)
if (inst == driver_id)
ret = -EINVAL;
if (ret == 0 && clk->enable_count++ == 0) {
ret = clk->ops->enable(clk);
if (ret)
clk->enable_count--;
}
spin_unlock_irqrestore(&clk->lock, flags);
}
return ret;
}
I think that's going completely over the top, and adds needless complexity
to drivers, which now have to pass an instance specific cookie into every
clk API call.
On Fri, Feb 4, 2011 at 8:18 PM, Russell King - ARM Linux
<[email protected]> wrote:
> On Fri, Feb 04, 2011 at 08:04:03PM +0900, Jassi Brar wrote:
>> On Fri, Feb 4, 2011 at 7:48 PM, Russell King - ARM Linux
>> <[email protected]> wrote:
>>
>> > int clk_enable(struct clk *clk)
>> > {
>> > unsigned long flags;
>> > int ret = 0;
>> >
>> > if (clk) {
>> > if (WARN_ON(!clk->prepare_count))
>> > return -EINVAL;
>> >
>> > spin_lock_irqsave(&clk->lock, flags);
>> > if (clk->enable_count++ == 0)
>> > ret = clk->ops->enable(clk);
>> > spin_unlock_irqrestore(&clk->lock, flags);
>> > }
>> > return ret;
>> > }
>> >
>> > is entirely sufficient to catch the case of a single-use clock not being
>> > prepared before clk_enable() is called.
>> >
>> > We're after detecting drivers missing calls to clk_prepare(), we're not
>> > after detecting concurrent calls to clk_prepare()/clk_unprepare().
>>
>> I hope you mean 'making sure the clock is prepared before it's enabled
>> ' rather than
>> 'catching a driver that doesn't do clk_prepare before clk_enable'.
>> Because, the above implementation still doesn't catch a driver that
>> doesn't call clk_prepare
>> but simply uses a clock that happens to have been already prepare'd by
>> some other
>> driver or the platform.
>
> No, I mean what I said.
Then, how does that function catch a driver that, say, doesn't do clk_prepare
but share the clk with another already active driver?
Because you said - "We're after detecting drivers missing calls to
clk_prepare()"
The point is, there is difference between detecting drivers that miss
the clk_prepare
and ensuring clk_prepare has been called before any call to
clk_enable. And making
that clear helps get rid of lots of confusion/misunderstanding. Uwe
seems to have
had similar confusions.
> The only way to do what you're asking is to attach a list of identifiers
> which have prepared a clock to the struct clk, where each identifier is
> unique to each driver instance.
I am not asking what you think.
In my second last post, I am rather asking the other way around - that
let us not worry
about drivers missing the clk_prepare and not try to catch those by the new API.
> I think that's going completely over the top, and adds needless complexity
> to drivers, which now have to pass an instance specific cookie into every
> clk API call.
Exactly.
All we need is to ensure clk_prepare has been called atleast once before
any call to clk_enable.
On Fri, Feb 04, 2011 at 08:51:15PM +0900, Jassi Brar wrote:
> On Fri, Feb 4, 2011 at 8:18 PM, Russell King - ARM Linux
> <[email protected]> wrote:
> > On Fri, Feb 04, 2011 at 08:04:03PM +0900, Jassi Brar wrote:
> >> On Fri, Feb 4, 2011 at 7:48 PM, Russell King - ARM Linux
> >> <[email protected]> wrote:
> >>
> >> > int clk_enable(struct clk *clk)
> >> > {
> >> > ? ? ? ?unsigned long flags;
> >> > ? ? ? ?int ret = 0;
> >> >
> >> > ? ? ? ?if (clk) {
> >> > ? ? ? ? ? ? ? ?if (WARN_ON(!clk->prepare_count))
> >> > ? ? ? ? ? ? ? ? ? ? ? ?return -EINVAL;
> >> >
> >> > ? ? ? ? ? ? ? ?spin_lock_irqsave(&clk->lock, flags);
> >> > ? ? ? ? ? ? ? ?if (clk->enable_count++ == 0)
> >> > ? ? ? ? ? ? ? ? ? ? ? ?ret = clk->ops->enable(clk);
> >> > ? ? ? ? ? ? ? ?spin_unlock_irqrestore(&clk->lock, flags);
> >> > ? ? ? ?}
> >> > ? ? ? ?return ret;
> >> > }
> >> >
> >> > is entirely sufficient to catch the case of a single-use clock not being
> >> > prepared before clk_enable() is called.
> >> >
> >> > We're after detecting drivers missing calls to clk_prepare(), we're not
> >> > after detecting concurrent calls to clk_prepare()/clk_unprepare().
> >>
> >> I hope you mean 'making sure the clock is prepared before it's enabled
> >> ' rather than
> >> 'catching a driver that doesn't do clk_prepare before clk_enable'.
> >> Because, the above implementation still doesn't catch a driver that
> >> doesn't call clk_prepare
> >> but simply uses a clock that happens to have been already prepare'd by
> >> some other
> >> driver or the platform.
> >
> > No, I mean what I said.
> Then, how does that function catch a driver that, say, doesn't do clk_prepare
> but share the clk with another already active driver?
As per the code I just supplied!
> Because you said - "We're after detecting drivers missing calls to
> clk_prepare()"
>
> The point is, there is difference between detecting drivers that miss
> the clk_prepare
> and ensuring clk_prepare has been called before any call to
> clk_enable. And making
> that clear helps get rid of lots of confusion/misunderstanding. Uwe
> seems to have
> had similar confusions.
As I said on the 1st February.
> > The only way to do what you're asking is to attach a list of identifiers
> > which have prepared a clock to the struct clk, where each identifier is
> > unique to each driver instance.
> I am not asking what you think.
> In my second last post, I am rather asking the other way around - that
> let us not worry
> about drivers missing the clk_prepare and not try to catch those by the
> new API.
No. That means we have no way to flag a call to clk_enable on an
unprepared clock, and will lead to unexplained system lockups. What
I've been suggesting all along is the "best efforts" approach. I'm
sorry you can't see that, but that's really not my problem.
> > I think that's going completely over the top, and adds needless complexity
> > to drivers, which now have to pass an instance specific cookie into every
> > clk API call.
> Exactly.
> All we need is to ensure clk_prepare has been called atleast once before
> any call to clk_enable.
I described this fully in my reply to Stephen Boyd on 1st February,
which is a parent to this sub-thread.
On Tue, Feb 01, 2011 at 05:11:29PM +0800, Jeremy Kerr wrote:
> Hi all,
>
> > I suggested that clk_prepare() be callable only from non-atomic contexts,
> > and do whatever's required to ensure that the clock is available. That
> > may end up enabling the clock as a result.
>
> I think that clk_prepare/clk_unprepare looks like the most promising solution,
> so will try to get some preliminary patches done. Here's what I'm planning:
>
> -----
>
> The changes to the API are essentially:
>
> 1) Document clk_enable/clk_disable as callable from atomic contexts, and
> so clock implementations must not sleep within this function.
>
> 2) For clock implementations that may sleep to turn on a clock, we add a
> new pair of functions to the clock API: clk_prepare and clk_unprepare.
>
> These will provide hooks for the clock implmentation to do any sleepable
> work (eg, wait for PLLs to settle) in preparation for a later clk_enable.
>
> For the most common clock implemntation cases (where clocks can be enabled
> atomically), these functions will be a no-op, and all of the enable/disable
> work can be done in clk_enable/clk_disable.
>
> For implementations where clocks require blocking on enable/disable, most
> of the work will be done in clk_prepare/clk_unprepare. The clk_enable
> and clk_disable functions may be no-ops.
>
> For drivers, this means that clk_prepare must be called (and have returned)
> before calling clk_enable.
>
> == Enable/Prepare counts ==
>
> I intend to do the enable and prepare "counting" in the core clock API,
> meaning that that the clk_ops callbacks will only invoked on the first
> prepare/enable and the last unprepare/disable.
>
> == Concurrency ==
>
> Splitting the prepare and enable stages introduces the concurrency
> requirements:
>
> 1) clk_enable must not return before the clock is outputting a valid clock
> signal.
>
> 2) clk_prepare must not return before the clock is fully prepared (ie, it is
> safe to call clk_enable).
>
> It is not possible for clk_enable to wait for the clock to be prepared,
> because that would require synchronisation with clk_prepare, which may then
> require blocking. Therefore:
>
> 3) The clock consumer *must* respect the proper ordering of clk_prepare and
> clk_enable. For example, drivers that call clk_enable during an interrupt
> must ensure that the interrupt handler will not be invoked until
> clk_prepare has returned.
>
> == Other considerations ==
>
> The time that a clock spends "prepared" is a superset of the the time that a
> clock spends "enabled". Therefore, clocks that are switched on during
> clk_prepare (ie, non-atomic clocks) will be running for a larger amount of
> time. In some cases, this can be mitigated by moving some of the final
> (atomic) switching functionality to the clk_enable function.
>
> == Implementation ==
>
> Basically:
>
> struct clk {
> const struct clk_ops *ops
> int enable_count;
> spinlock_t enable_lock;
> int prepare_count;
> struct mutex prepare_lock;
> };
>
> int clk_enable(struct clk *clk)
> {
> int ret = 0;
>
> spin_lock(&clk->enable_lock);
> if (!clk->enable_count)
> ret = clk->ops->enable(clk);
>
> if (!ret)
> clk->enable_count++;
> spin_unlock(&clk->enable_lock);
>
> return ret;
> }
Why do we not call parent's clk_enable in this function? For flexible? How many
different cases is causing us to move the effert to platform clock driver?
>
> int clk_prepare(struct clk *clk)
> {
> int ret = 0;
>
> mutex_lock(&clk->prepare_lock);
> if (!clk->prepare_count)
> ret = clk->ops->prepare(clk);
>
> if (!ret)
> clk->prepare_count++;
> mutex_unlock(&clk->prepare_lock);
>
> return ret;
> }
Same as above.
And for most clocks, prepare/unprepare may be NULL. So in such case, is it
better to call parent's prepare and increase its own prepare_count here?
Thanks
Richard
>
> -----
>
> Comments welcome, code coming soon.
>
> Cheers,
>
>
> Jeremy
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, Feb 04, 2011 at 08:45:34PM +0800, Richard Zhao wrote:
> > == Implementation ==
> >
> > Basically:
> >
> > struct clk {
> > const struct clk_ops *ops
> > int enable_count;
> > spinlock_t enable_lock;
> > int prepare_count;
> > struct mutex prepare_lock;
> > };
> >
> > int clk_enable(struct clk *clk)
> > {
> > int ret = 0;
> >
> > spin_lock(&clk->enable_lock);
> > if (!clk->enable_count)
> > ret = clk->ops->enable(clk);
> >
> > if (!ret)
> > clk->enable_count++;
> > spin_unlock(&clk->enable_lock);
> >
> > return ret;
> > }
> Why do we not call parent's clk_enable in this function? For flexible? How many
> different cases is causing us to move the effert to platform clock driver?
You may notice that struct clk above doesn't have a parent.
We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.
This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.
This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.
Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:
struct clk {
const struct clk_ops *ops;
unsigned int enable_count;
unsigned int prepare_count;
spinlock_t enable_lock;
struct mutex prepare_lock;
};
And a set of clock operations (defined per type of clock):
struct clk_ops {
int (*enable)(struct clk *);
void (*disable)(struct clk *);
unsigned long (*get_rate)(struct clk *);
[...]
};
To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:
struct clk_foo {
struct clk clk;
void __iomem *some_register;
};
struct clk_ops clk_foo_ops = {
.get_rate = clk_foo_get_rate,
};
The common clock definitions are based on a development patch from Ben
Herrenschmidt <[email protected]>.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/Kconfig | 3
drivers/clk/Makefile | 1
drivers/clk/clk.c | 134 +++++++++++++++++++++++++++++++
drivers/clk/clkdev.c | 5 +
include/linux/clk.h | 184 ++++++++++++++++++++++++++++++++++++++++---
5 files changed, 318 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
config CLKDEV_LOOKUP
bool
select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+ bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..12e0daf
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+ int ret = 0;
+
+ if (!clk->ops->prepare)
+ return 0;
+
+ mutex_lock(&clk->prepare_lock);
+ if (clk->prepare_count == 0)
+ ret = clk->ops->prepare(clk);
+
+ if (!ret)
+ clk->prepare_count++;
+ mutex_unlock(&clk->prepare_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+ if (!clk->ops->unprepare)
+ return;
+
+ mutex_lock(&clk->prepare_lock);
+ if (--clk->prepare_count == 0)
+ clk->ops->unprepare(clk);
+
+ mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (!clk->ops->enable)
+ return 0;
+
+ spin_lock(&clk->enable_lock);
+ if (!clk->enable_count)
+ ret = clk->ops->enable(clk);
+
+ if (!ret)
+ clk->enable_count++;
+ spin_unlock(&clk->enable_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ if (!clk->ops->disable)
+ return;
+
+ spin_lock(&clk->enable_lock);
+
+ WARN_ON(!clk->enable_count);
+
+ if (!--clk->enable_count)
+ clk->ops->disable(clk);
+
+ spin_unlock(&clk->enable_lock);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk->ops->get_rate)
+ return clk->ops->get_rate(clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int __clk_get(struct clk *clk)
+{
+ if (clk->ops->get)
+ return clk->ops->get(clk);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(__clk_get);
+
+void clk_put(struct clk *clk)
+{
+ if (clk->ops->put)
+ clk->ops->put(clk);
+}
+EXPORT_SYMBOL_GPL(clk_put);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->ops->round_rate)
+ return clk->ops->round_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->ops->set_rate)
+ return clk->ops->set_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (clk->ops->set_parent)
+ return clk->ops->set_parent(clk, parent);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (clk->ops->get_parent)
+ return clk->ops->get_parent(clk);
+ return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..17619c7 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -84,12 +84,17 @@ struct clk *clk_get(struct device *dev, const char *con_id)
}
EXPORT_SYMBOL(clk_get);
+#ifndef CONFIG_USE_COMMON_STRUCT_CLK
+/* For the common struct clk case, clk_put is provided by clk.c */
+
void clk_put(struct clk *clk)
{
__clk_put(clk);
}
EXPORT_SYMBOL(clk_put);
+#endif
+
void clkdev_add(struct clk_lookup *cl)
{
mutex_lock(&clocks_mutex);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..e081ca1 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
+ * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,189 @@
#ifndef __LINUX_CLK_H
#define __LINUX_CLK_H
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
struct device;
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops: implementation-specific ops for this clock
+ * @enable_count: count of clk_enable() calls active on this clock
+ * @flags: platform-independent flags
+ * @lock: lock for enable/disable or other HW-specific ops
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ * struct clk_foo {
+ * struct clk;
+ * [device specific fields]
+ * };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @lock member provides either a spinlock or a mutex to protect (at least)
+ * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
+ * set, then the core clock code will use a spinlock, otherwise a mutex. This
+ * lock will be acquired during clk_enable and clk_disable, so for atomic
+ * clocks, these ops callbacks must not sleep.
+ *
+ * The choice of atomic or non-atomic clock depends on how the clock is enabled.
+ * Typically, you'll want to use a non-atomic clock. For clocks that need to be
+ * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
+ * clocks with parents will typically cascade enable/disable operations to
+ * their parent, so the parent of an atomic clock *must* be atomic too.
*/
+struct clk {
+ const struct clk_ops *ops;
+ unsigned int enable_count;
+ unsigned int prepare_count;
+ spinlock_t enable_lock;
+ struct mutex prepare_lock;
+};
+
+/* static initialiser for non-atomic clocks */
+#define INIT_CLK(name, o) { \
+ .ops = &o, \
+ .enable_count = 0, \
+ .prepare_count = 0, \
+ .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
+ .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
+}
+/**
+ * struct clk_ops - Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare: Prepare the clock for enabling. This must not return until
+ * the clock is fully prepared, and it's safe to call clk_enable.
+ * This callback is intended to allow clock implementations to
+ * do any initialisation that may block. Called with
+ * clk->prepare_lock held.
+ *
+ * @unprepare: Release the clock from its prepared state. This will typically
+ * undo any work done in the @prepare callback. Called with
+ * clk->prepare_lock held.
+ *
+ * @enable: Enable the clock atomically. This must not return until the
+ * clock is generating a valid clock signal, usable by consumer
+ * devices. Called with clk->enable_lock held.
+ *
+ * @disable: Disable the clock atomically. Called with clk->enable_lock held.
+ *
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts. If a clock requires blocking code to be turned on, this
+ * should be done in clk_prepare. Switching that will not block should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt).
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see kernel/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+ int (*prepare)(struct clk *);
+ void (*unprepare)(struct clk *);
+ int (*enable)(struct clk *);
+ void (*disable)(struct clk *);
+ int (*get)(struct clk *);
+ void (*put)(struct clk *);
+ unsigned long (*get_rate)(struct clk *);
+ long (*round_rate)(struct clk *, unsigned long);
+ int (*set_rate)(struct clk *, unsigned long);
+ int (*set_parent)(struct clk *, struct clk *);
+ struct clk * (*get_parent)(struct clk *);
+};
+
+/**
+ * __clk_get - update clock-specific refcounter
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function; it is only needed by the
+ * arch-specific clk_get() implementations.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any blocking initialisation on @clk, allowing the clock to be later
+ * enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possbly blocking) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+ clk->enable_count = clk->prepare_count = 0;
+ spin_lock_init(&clk->enable_lock);
+ mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
*/
struct clk;
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+int clk_prepare(struct clk *clk) { return 0; }
+void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
/**
* clk_get - lookup and obtain a reference to a clock producer.
* @dev: device for clock "consumer"
@@ -83,12 +255,6 @@ unsigned long clk_get_rate(struct clk *clk);
*/
void clk_put(struct clk *clk);
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
/**
* clk_round_rate - adjust a rate to the exact rate a clock can provide
* @clk: clock source
Hi all,
These patches are an attempt to allow platforms to share clock code. At
present, the definitions of 'struct clk' are local to platform code,
which makes allocating and initialising cross-platform clock sources
difficult, and makes it impossible to compile a single image containing
support for two ARM platforms with different struct clks.
The three patches are for the architecture-independent kernel code,
introducing the common clk infrastructure. The changelog for the first
patch includes details about the new clock definitions.
Ben Herrenschmidt is looking at using common struct clk code for powerpc
too, hence the kernel-wide approach.
Many thanks to the following for their input:
* Ben Dooks <[email protected]>
* Baruch Siach <[email protected]>
* Russell King <[email protected]>
* Uwe Kleine-König <[email protected]>
* Lorenzo Pieralisi <[email protected]>
* Vincent Guittot <[email protected]>
* Sascha Hauer <[email protected]>
Cheers,
Jeremy
--
v11:
* add prepare/unprepare for non-atomic switching, document atomicity
* move to drivers/clk/
v10:
* comment fixups, from Uwe's review
* added DEFINE_CLK_FIXED
v9:
* comment improvements
* kerneldoc fixups
* add WARN_ON to clk_disable
v8:
* add atomic clocks, and locking wrappers
* expand comments on clk and clk_ops
v7:
* change CLK_INIT to initialise clk->mutex statically
v6:
* fixed up references to 'clk_operations' in the changelog
v5:
* uninline main API, and share definitions with !USE_COMMON_STRUCT_CLK
* add __clk_get
* delay mutex init
* kerneldoc for struct clk
v4:
* use mutex for enable/disable locking
* DEFINE_CLK -> INIT_CLK, and pass the clk name for mutex init
* struct clk_operations -> struct clk_ops
v3:
* do clock usage refcounting in common code
* provide sample port
v2:
* no longer ARM-specific
* use clk_operations
---
Jeremy Kerr (3):
Add a common struct clk
clk: Generic support for fixed-rate clocks
clk: add warnings for incorrect enable/prepare semantics
Since most platforms will need a fixed-rate clock, add one. This will
also serve as a basic example of an implementation of struct clk.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/clk.c | 14 ++++++++++++++
include/linux/clk.h | 16 ++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 12e0daf..51dbd33 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -132,3 +132,17 @@ struct clk *clk_get_parent(struct clk *clk)
return ERR_PTR(-ENOSYS);
}
EXPORT_SYMBOL_GPL(clk_get_parent);
+
+/* clk_fixed support */
+
+#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
+
+static unsigned long clk_fixed_get_rate(struct clk *clk)
+{
+ return to_clk_fixed(clk)->rate;
+}
+
+struct clk_ops clk_fixed_ops = {
+ .get_rate = clk_fixed_get_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_ops);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index e081ca1..daa2d5a 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -176,6 +176,22 @@ static inline void clk_common_init(struct clk *clk)
mutex_init(&clk->prepare_lock);
}
+/* Simple fixed-rate clock */
+struct clk_fixed {
+ struct clk clk;
+ unsigned long rate;
+};
+
+extern struct clk_ops clk_fixed_ops;
+
+#define INIT_CLK_FIXED(name, r) { \
+ .clk = INIT_CLK(name.clk, clk_fixed_ops), \
+ .rate = (r) \
+}
+
+#define DEFINE_CLK_FIXED(name, r) \
+ struct clk_fixed name = INIT_CLK_FIXED(name, r)
+
#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
This change adds warnings to check for:
1) enabling a clock that hasn't been prepared; and
2) unpreparing a clock that is still enabled
While the correctness can't be guaranteed, these warnings should cover
most situations.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/clk.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 51dbd33..2369959 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -35,6 +35,8 @@ void clk_unprepare(struct clk *clk)
if (!clk->ops->unprepare)
return;
+ WARN_ON(clk->enable_count);
+
mutex_lock(&clk->prepare_lock);
if (--clk->prepare_count == 0)
clk->ops->unprepare(clk);
@@ -50,6 +52,8 @@ int clk_enable(struct clk *clk)
if (!clk->ops->enable)
return 0;
+ WARN_ON(clk->ops->prepare && clk->prepare_count);
+
spin_lock(&clk->enable_lock);
if (!clk->enable_count)
ret = clk->ops->enable(clk);
On Mon, Feb 7, 2011 at 3:07 PM, Jeremy Kerr <[email protected]> wrote:
> This change adds warnings to check for:
>
> 1) enabling a clock that hasn't been prepared; and
>
> 2) unpreparing a clock that is still enabled
>
> While the correctness can't be guaranteed, these warnings should cover
> most situations.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/clk.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 51dbd33..2369959 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -35,6 +35,8 @@ void clk_unprepare(struct clk *clk)
> if (!clk->ops->unprepare)
> return;
>
> + WARN_ON(clk->enable_count);
> +
> mutex_lock(&clk->prepare_lock);
> if (--clk->prepare_count == 0)
> clk->ops->unprepare(clk);
> @@ -50,6 +52,8 @@ int clk_enable(struct clk *clk)
> if (!clk->ops->enable)
> return 0;
>
> + WARN_ON(clk->ops->prepare && clk->prepare_count);
> +
Shouldn't the prepare_count be checked against 0 ?
Hi Jassi,
> Shouldn't the prepare_count be checked against 0 ?
Yes, you're right, it should be clk->prepare_count == 0.
Will update for the next revision.
Cheers,
Jeremy
On Mon, Feb 07, 2011 at 02:07:57PM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> const struct clk_ops *ops;
> unsigned int enable_count;
> unsigned int prepare_count;
> spinlock_t enable_lock;
> struct mutex prepare_lock;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_ops {
> int (*enable)(struct clk *);
> void (*disable)(struct clk *);
> unsigned long (*get_rate)(struct clk *);
> [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
> struct clk clk;
> void __iomem *some_register;
> };
>
> struct clk_ops clk_foo_ops = {
> .get_rate = clk_foo_get_rate,
> };
>
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <[email protected]>.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/Kconfig | 3
> drivers/clk/Makefile | 1
> drivers/clk/clk.c | 134 +++++++++++++++++++++++++++++++
> drivers/clk/clkdev.c | 5 +
> include/linux/clk.h | 184 ++++++++++++++++++++++++++++++++++++++++---
> 5 files changed, 318 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 4168c88..6e3ae54 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -2,3 +2,6 @@
> config CLKDEV_LOOKUP
> bool
> select HAVE_CLK
> +
> +config USE_COMMON_STRUCT_CLK
> + bool
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 07613fa..a1a06d3 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -1,2 +1,3 @@
>
> obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> new file mode 100644
> index 0000000..12e0daf
> --- /dev/null
> +++ b/drivers/clk/clk.c
> @@ -0,0 +1,134 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +
> +int clk_prepare(struct clk *clk)
> +{
> + int ret = 0;
> +
> + if (!clk->ops->prepare)
> + return 0;
> +
> + mutex_lock(&clk->prepare_lock);
> + if (clk->prepare_count == 0)
> + ret = clk->ops->prepare(clk);
> +
> + if (!ret)
> + clk->prepare_count++;
> + mutex_unlock(&clk->prepare_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_prepare);
> +
> +void clk_unprepare(struct clk *clk)
> +{
> + if (!clk->ops->unprepare)
> + return;
> +
> + mutex_lock(&clk->prepare_lock);
> + if (--clk->prepare_count == 0)
> + clk->ops->unprepare(clk);
> +
> + mutex_unlock(&clk->prepare_lock);
> +}
> +EXPORT_SYMBOL_GPL(clk_unprepare);
> +
> +int clk_enable(struct clk *clk)
> +{
> + int ret = 0;
> +
Did we want to check for prepare_count > 0 here? Russell's suggestion
was to do that without holding any lock.
(To make this a tad safer, you could use
ACCESS_ONCE(clk->enable_count)++ below. (Suggested by paulmck on irc.))
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Hello Jeremy,
On Mon, Feb 07, 2011 at 02:07:57PM +0800, Jeremy Kerr wrote:
> This change adds warnings to check for:
>
> 1) enabling a clock that hasn't been prepared; and
>
> 2) unpreparing a clock that is still enabled
>
> While the correctness can't be guaranteed, these warnings should cover
> most situations.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/clk.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 51dbd33..2369959 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -35,6 +35,8 @@ void clk_unprepare(struct clk *clk)
> if (!clk->ops->unprepare)
> return;
>
> + WARN_ON(clk->enable_count);
> +
> mutex_lock(&clk->prepare_lock);
> if (--clk->prepare_count == 0)
> clk->ops->unprepare(clk);
> @@ -50,6 +52,8 @@ int clk_enable(struct clk *clk)
> if (!clk->ops->enable)
> return 0;
>
> + WARN_ON(clk->ops->prepare && clk->prepare_count);
> +
This implies the warning is only issued on clocks that have a prepare
callback. If we want to enforce the new API the warning here shouldn't
depend on clk->ops->prepare. (clk_prepare and clk_unprepare need to
be changed then to adapt the prepare_count even in the absence of
clk->ops->prepare.)
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Hi Uwe,
> This implies the warning is only issued on clocks that have a prepare
> callback. If we want to enforce the new API the warning here shouldn't
> depend on clk->ops->prepare. (clk_prepare and clk_unprepare need to
> be changed then to adapt the prepare_count even in the absence of
> clk->ops->prepare.)
Yeah, it's a decision about either adding a small cost to all clk_prepare()s
(ie, adding cost when there is no prepare callback), or checking for the
correct prepare/enable semantics for all clocks (even when it doesn't matter
for that particular clock). I chose the first as more important, but happy to
go either way here.
Cheers,
Jeremy
On Mon, Feb 07, 2011 at 02:07:57PM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> const struct clk_ops *ops;
> unsigned int enable_count;
> unsigned int prepare_count;
> spinlock_t enable_lock;
> struct mutex prepare_lock;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_ops {
> int (*enable)(struct clk *);
> void (*disable)(struct clk *);
> unsigned long (*get_rate)(struct clk *);
> [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
> struct clk clk;
> void __iomem *some_register;
> };
>
> struct clk_ops clk_foo_ops = {
> .get_rate = clk_foo_get_rate,
> };
>
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <[email protected]>.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/Kconfig | 3
> drivers/clk/Makefile | 1
> drivers/clk/clk.c | 134 +++++++++++++++++++++++++++++++
> drivers/clk/clkdev.c | 5 +
> include/linux/clk.h | 184 ++++++++++++++++++++++++++++++++++++++++---
> 5 files changed, 318 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 4168c88..6e3ae54 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -2,3 +2,6 @@
> config CLKDEV_LOOKUP
> bool
> select HAVE_CLK
> +
> +config USE_COMMON_STRUCT_CLK
> + bool
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 07613fa..a1a06d3 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -1,2 +1,3 @@
>
> obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> new file mode 100644
> index 0000000..12e0daf
> --- /dev/null
> +++ b/drivers/clk/clk.c
> @@ -0,0 +1,134 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +
> +int clk_prepare(struct clk *clk)
> +{
> + int ret = 0;
> +
> + if (!clk->ops->prepare)
> + return 0;
> +
> + mutex_lock(&clk->prepare_lock);
> + if (clk->prepare_count == 0)
> + ret = clk->ops->prepare(clk);
> +
> + if (!ret)
> + clk->prepare_count++;
> + mutex_unlock(&clk->prepare_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_prepare);
> +
> +void clk_unprepare(struct clk *clk)
> +{
> + if (!clk->ops->unprepare)
> + return;
> +
> + mutex_lock(&clk->prepare_lock);
> + if (--clk->prepare_count == 0)
> + clk->ops->unprepare(clk);
> +
> + mutex_unlock(&clk->prepare_lock);
> +}
> +EXPORT_SYMBOL_GPL(clk_unprepare);
> +
> +int clk_enable(struct clk *clk)
> +{
> + int ret = 0;
> +
> + if (!clk->ops->enable)
> + return 0;
> +
> + spin_lock(&clk->enable_lock);
> + if (!clk->enable_count)
> + ret = clk->ops->enable(clk);
> +
> + if (!ret)
> + clk->enable_count++;
> + spin_unlock(&clk->enable_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> + if (!clk->ops->disable)
> + return;
> +
> + spin_lock(&clk->enable_lock);
> +
> + WARN_ON(!clk->enable_count);
> +
> + if (!--clk->enable_count)
> + clk->ops->disable(clk);
> +
> + spin_unlock(&clk->enable_lock);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> + if (clk->ops->get_rate)
> + return clk->ops->get_rate(clk);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +int __clk_get(struct clk *clk)
> +{
> + if (clk->ops->get)
> + return clk->ops->get(clk);
> + return 1;
> +}
> +EXPORT_SYMBOL_GPL(__clk_get);
> +
> +void clk_put(struct clk *clk)
> +{
> + if (clk->ops->put)
> + clk->ops->put(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_put);
> +
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->round_rate)
> + return clk->ops->round_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->set_rate)
> + return clk->ops->set_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> + if (clk->ops->set_parent)
> + return clk->ops->set_parent(clk, parent);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> + if (clk->ops->get_parent)
> + return clk->ops->get_parent(clk);
> + return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
> diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
> index 0fc0a79..17619c7 100644
> --- a/drivers/clk/clkdev.c
> +++ b/drivers/clk/clkdev.c
> @@ -84,12 +84,17 @@ struct clk *clk_get(struct device *dev, const char *con_id)
> }
> EXPORT_SYMBOL(clk_get);
>
> +#ifndef CONFIG_USE_COMMON_STRUCT_CLK
> +/* For the common struct clk case, clk_put is provided by clk.c */
> +
> void clk_put(struct clk *clk)
> {
> __clk_put(clk);
> }
> EXPORT_SYMBOL(clk_put);
>
> +#endif
> +
> void clkdev_add(struct clk_lookup *cl)
> {
> mutex_lock(&clocks_mutex);
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..e081ca1 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
> *
> * Copyright (C) 2004 ARM Limited.
> * Written by Deep Blue Solutions Limited.
> + * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,189 @@
> #ifndef __LINUX_CLK_H
> #define __LINUX_CLK_H
>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +
> struct device;
>
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @ops: implementation-specific ops for this clock
> + * @enable_count: count of clk_enable() calls active on this clock
> + * @flags: platform-independent flags
> + * @lock: lock for enable/disable or other HW-specific ops
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + * struct clk_foo {
> + * struct clk;
> + * [device specific fields]
> + * };
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @lock member provides either a spinlock or a mutex to protect (at least)
> + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> + * lock will be acquired during clk_enable and clk_disable, so for atomic
> + * clocks, these ops callbacks must not sleep.
> + *
> + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> + * clocks with parents will typically cascade enable/disable operations to
> + * their parent, so the parent of an atomic clock *must* be atomic too.
> */
This comment needs a general overhaul.
(I had this comment already in my first mail, but I must have deleted it
when removing the unrealted quotes.)
> +struct clk {
> + const struct clk_ops *ops;
> + unsigned int enable_count;
> + unsigned int prepare_count;
> + spinlock_t enable_lock;
> + struct mutex prepare_lock;
> +};
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Hi Dima,
> > +int clk_prepare(struct clk *clk)
> > +{
> > + int ret = 0;
> > +
> > + if (!clk->ops->prepare)
> > + return 0;
> > +
> > + mutex_lock(&clk->prepare_lock);
> > + if (clk->prepare_count == 0)
> > + ret = clk->ops->prepare(clk);
> > +
> > + if (!ret)
> > + clk->prepare_count++;
> > + mutex_unlock(&clk->prepare_lock);
> > +
> > + return 0;
>
> return ret;
Good catch, thanks.
Jeremy
On Mon, 7 Feb 2011, Jeremy Kerr wrote:
> Hi Uwe,
>
> > This implies the warning is only issued on clocks that have a prepare
> > callback. If we want to enforce the new API the warning here shouldn't
> > depend on clk->ops->prepare. (clk_prepare and clk_unprepare need to
> > be changed then to adapt the prepare_count even in the absence of
> > clk->ops->prepare.)
>
> Yeah, it's a decision about either adding a small cost to all clk_prepare()s
> (ie, adding cost when there is no prepare callback), or checking for the
> correct prepare/enable semantics for all clocks (even when it doesn't matter
> for that particular clock). I chose the first as more important, but happy to
> go either way here.
The prepare method being called from non-atomic context cannot be
considered to be in a speed critical path. Most of the time, this is
going to be called on driver initialization or the like, and that's a
relatively rare event. Therefore this really small cost to clk_prepare()
is definitively worth it to help proper usage of the API. If this ever
becomes a problem then this could be confined to some CONFIG_CLK_DEBUG
or the like. But when introducing a new API it is best to be more
strict to help people get its usage right (without going overboard with
it of course).
Nicolas
On Sun, Feb 6, 2011 at 10:07 PM, Jeremy Kerr <[email protected]> wrote:
<snip>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> new file mode 100644
> index 0000000..12e0daf
> --- /dev/null
> +++ b/drivers/clk/clk.c
<snip>
> +int clk_enable(struct clk *clk)
> +{
> + ? ? ? int ret = 0;
> +
> + ? ? ? if (!clk->ops->enable)
> + ? ? ? ? ? ? ? return 0;
> +
> + ? ? ? spin_lock(&clk->enable_lock);
spin_lock_irqsave/spin_unlock_irqrestore. This could get called with
irqs on or off.
On 02/07/2011 07:07 PM, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
Hi Jeremy,
Quick review below.
~Ryan
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> const struct clk_ops *ops;
> unsigned int enable_count;
> unsigned int prepare_count;
> spinlock_t enable_lock;
> struct mutex prepare_lock;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_ops {
> int (*enable)(struct clk *);
> void (*disable)(struct clk *);
> unsigned long (*get_rate)(struct clk *);
> [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
> struct clk clk;
> void __iomem *some_register;
> };
>
> struct clk_ops clk_foo_ops = {
> .get_rate = clk_foo_get_rate,
> };
>
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <[email protected]>.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/Kconfig | 3
> drivers/clk/Makefile | 1
> drivers/clk/clk.c | 134 +++++++++++++++++++++++++++++++
> drivers/clk/clkdev.c | 5 +
> include/linux/clk.h | 184 ++++++++++++++++++++++++++++++++++++++++---
> 5 files changed, 318 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 4168c88..6e3ae54 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -2,3 +2,6 @@
> config CLKDEV_LOOKUP
> bool
> select HAVE_CLK
> +
> +config USE_COMMON_STRUCT_CLK
> + bool
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 07613fa..a1a06d3 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -1,2 +1,3 @@
>
> obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> new file mode 100644
> index 0000000..12e0daf
> --- /dev/null
> +++ b/drivers/clk/clk.c
> @@ -0,0 +1,134 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +
> +int clk_prepare(struct clk *clk)
> +{
> + int ret = 0;
> +
> + if (!clk->ops->prepare)
> + return 0;
If there is no ops->prepare function then we never increment
prepare_count, which means that driver writers can get sloppy if they
know that ops->prepare is no-op on their platform since they will not
get warned for omitting clk_prepare.
Also, why are the warnings added in a separate patch rather than being
rolled into this patch?
> +
> + mutex_lock(&clk->prepare_lock);
> + if (clk->prepare_count == 0)
> + ret = clk->ops->prepare(clk);
> +
> + if (!ret)
> + clk->prepare_count++;
> + mutex_unlock(&clk->prepare_lock);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_prepare);
> +
> +void clk_unprepare(struct clk *clk)
> +{
> + if (!clk->ops->unprepare)
> + return;
> +
> + mutex_lock(&clk->prepare_lock);
> + if (--clk->prepare_count == 0)
> + clk->ops->unprepare(clk);
> +
> + mutex_unlock(&clk->prepare_lock);
> +}
> +EXPORT_SYMBOL_GPL(clk_unprepare);
> +
> +int clk_enable(struct clk *clk)
> +{
> + int ret = 0;
> +
> + if (!clk->ops->enable)
> + return 0;
Again, you should still increment enable_count even if ops->enabled is a
no-op since it provides valuable warnings when clk_enable/disable calls
are not matched correctly.
> +
> + spin_lock(&clk->enable_lock);
> + if (!clk->enable_count)
> + ret = clk->ops->enable(clk);
> +
> + if (!ret)
> + clk->enable_count++;
> + spin_unlock(&clk->enable_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> + if (!clk->ops->disable)
> + return;
> +
> + spin_lock(&clk->enable_lock);
> +
> + WARN_ON(!clk->enable_count);
> +
> + if (!--clk->enable_count)
> + clk->ops->disable(clk);
> +
> + spin_unlock(&clk->enable_lock);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> + if (clk->ops->get_rate)
> + return clk->ops->get_rate(clk);
Possibly we should shadow the clock rate if ops->get_rate is no-op? So
clock initialisation and clk_set_rate store the rate in the shadow
field, and then do:
if (clk->ops->get_rate)
return clk->ops->get_rate(clk);
return clk->shadow_rate;
Because the API is generic, driver writers should reasonably expect that
clk_get_rate will return something valid without having to know the
platform implementation details. It may also be worth having a warning
to let the user know that the returned rate may be approximate.
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +int __clk_get(struct clk *clk)
> +{
> + if (clk->ops->get)
> + return clk->ops->get(clk);
> + return 1;
> +}
> +EXPORT_SYMBOL_GPL(__clk_get);
> +
> +void clk_put(struct clk *clk)
> +{
> + if (clk->ops->put)
> + clk->ops->put(clk);
> +}
> +EXPORT_SYMBOL_GPL(clk_put);
This has probably been covered, and I have probably missed it, but why
don't the generic clk_get/put functions do ref-counting? Drivers must
have matched clk_get/put calls so it should work like enable/prepare
counting right?
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->round_rate)
> + return clk->ops->round_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->set_rate)
> + return clk->ops->set_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> + if (clk->ops->set_parent)
> + return clk->ops->set_parent(clk, parent);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> + if (clk->ops->get_parent)
> + return clk->ops->get_parent(clk);
> + return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
> diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
> index 0fc0a79..17619c7 100644
> --- a/drivers/clk/clkdev.c
> +++ b/drivers/clk/clkdev.c
> @@ -84,12 +84,17 @@ struct clk *clk_get(struct device *dev, const char *con_id)
> }
> EXPORT_SYMBOL(clk_get);
>
> +#ifndef CONFIG_USE_COMMON_STRUCT_CLK
> +/* For the common struct clk case, clk_put is provided by clk.c */
> +
> void clk_put(struct clk *clk)
> {
> __clk_put(clk);
> }
> EXPORT_SYMBOL(clk_put);
>
> +#endif
> +
> void clkdev_add(struct clk_lookup *cl)
> {
> mutex_lock(&clocks_mutex);
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..e081ca1 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
> *
> * Copyright (C) 2004 ARM Limited.
> * Written by Deep Blue Solutions Limited.
> + * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,189 @@
> #ifndef __LINUX_CLK_H
> #define __LINUX_CLK_H
>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +
> struct device;
>
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @ops: implementation-specific ops for this clock
> + * @enable_count: count of clk_enable() calls active on this clock
> + * @flags: platform-independent flags
> + * @lock: lock for enable/disable or other HW-specific ops
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + * struct clk_foo {
> + * struct clk;
> + * [device specific fields]
> + * };
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @lock member provides either a spinlock or a mutex to protect (at least)
> + * @enable_count. The type of lock used will depend on @flags; if CLK_ATOMIC is
> + * set, then the core clock code will use a spinlock, otherwise a mutex. This
> + * lock will be acquired during clk_enable and clk_disable, so for atomic
> + * clocks, these ops callbacks must not sleep.
> + *
> + * The choice of atomic or non-atomic clock depends on how the clock is enabled.
> + * Typically, you'll want to use a non-atomic clock. For clocks that need to be
> + * enabled/disabled in interrupt context, use CLK_ATOMIC. Note that atomic
> + * clocks with parents will typically cascade enable/disable operations to
> + * their parent, so the parent of an atomic clock *must* be atomic too.
This comment seems out of date now that we have the prepare/enable
semantics?
> */
> +struct clk {
> + const struct clk_ops *ops;
> + unsigned int enable_count;
> + unsigned int prepare_count;
> + spinlock_t enable_lock;
> + struct mutex prepare_lock;
> +};
> +
> +/* static initialiser for non-atomic clocks */
> +#define INIT_CLK(name, o) { \
> + .ops = &o, \
> + .enable_count = 0, \
> + .prepare_count = 0, \
> + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
> + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
> +}
>
> +/**
> + * struct clk_ops - Callback operations for clocks; these are to be provided
> + * by the clock implementation, and will be called by drivers through the clk_*
> + * API.
> + *
> + * @prepare: Prepare the clock for enabling. This must not return until
> + * the clock is fully prepared, and it's safe to call clk_enable.
> + * This callback is intended to allow clock implementations to
> + * do any initialisation that may block. Called with
> + * clk->prepare_lock held.
> + *
> + * @unprepare: Release the clock from its prepared state. This will typically
> + * undo any work done in the @prepare callback. Called with
> + * clk->prepare_lock held.
I think you need to make it more clear the prepare/unprepare must be
called from a sleepable context.
> + * @enable: Enable the clock atomically. This must not return until the
> + * clock is generating a valid clock signal, usable by consumer
> + * devices. Called with clk->enable_lock held.
> + *
> + * @disable: Disable the clock atomically. Called with clk->enable_lock held.
> + *
> + * @get: Called by the core clock code when a device driver acquires a
> + * clock via clk_get(). Optional.
> + *
> + * @put: Called by the core clock code when a devices driver releases a
> + * clock via clk_put(). Optional.
> + *
> + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
> + * implementations to split any work between atomic (enable) and sleepable
> + * (prepare) contexts. If a clock requires blocking code to be turned on, this
> + * should be done in clk_prepare. Switching that will not block should be done
> + * in clk_enable.
> + *
> + * Typically, drivers will call clk_prepare when a clock may be needed later
> + * (eg. when a device is opened), and clk_enable when the clock is actually
> + * required (eg. from an interrupt).
Drivers _must_ call clk_prepare before clk_enable (not typically)?
> + *
> + * For other callbacks, see the corresponding clk_* functions. Parameters and
> + * return values are passed directly from/to these API functions, or
> + * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
> + * is NULL, see kernel/clk.c for implementation details. All are optional.
> + */
> +struct clk_ops {
> + int (*prepare)(struct clk *);
> + void (*unprepare)(struct clk *);
> + int (*enable)(struct clk *);
> + void (*disable)(struct clk *);
> + int (*get)(struct clk *);
> + void (*put)(struct clk *);
> + unsigned long (*get_rate)(struct clk *);
> + long (*round_rate)(struct clk *, unsigned long);
> + int (*set_rate)(struct clk *, unsigned long);
> + int (*set_parent)(struct clk *, struct clk *);
> + struct clk * (*get_parent)(struct clk *);
> +};
> +
> +/**
> + * __clk_get - update clock-specific refcounter
> + *
> + * @clk: The clock to refcount
> + *
> + * Before a clock is returned from clk_get, this function should be called
> + * to update any clock-specific refcounting.
> + *
> + * Returns non-zero on success, zero on failure.
> + *
> + * Drivers should not need this function; it is only needed by the
> + * arch-specific clk_get() implementations.
> + */
> +int __clk_get(struct clk *clk);
I don't understand this. Are architectures supposed to provide a
function called clk_get? Doesn't this break the whole idea of having a
common struct clk?
> +/**
> + * clk_prepare - prepare clock for atomic enabling.
> + *
> + * @clk: The clock to prepare
> + *
> + * Do any blocking initialisation on @clk, allowing the clock to be later
> + * enabled atomically (via clk_enable). This function may sleep.
> + */
> +int clk_prepare(struct clk *clk);
> +
> +/**
> + * clk_unprepare - release clock from prepared state
> + *
> + * @clk: The clock to release
> + *
> + * Do any (possbly blocking) cleanup on clk. This function may sleep.
> + */
> +void clk_unprepare(struct clk *clk);
> +
> +/**
> + * clk_common_init - initialise a clock for driver usage
> + *
> + * @clk: The clock to initialise
> + *
> + * Used for runtime intialization of clocks; you don't need to call this
> + * if your clock has been (statically) initialized with INIT_CLK.
> + */
> +static inline void clk_common_init(struct clk *clk)
> +{
> + clk->enable_count = clk->prepare_count = 0;
> + spin_lock_init(&clk->enable_lock);
> + mutex_init(&clk->prepare_lock);
> +}
> +
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>
> /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
> */
> struct clk;
>
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +/*
> + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> + * functions are no-ops
> + */
> +int clk_prepare(struct clk *clk) { return 0; }
> +void clk_unprepare(struct clk *clk) { }
> +
> +#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
> +
> /**
> * clk_get - lookup and obtain a reference to a clock producer.
> * @dev: device for clock "consumer"
> @@ -83,12 +255,6 @@ unsigned long clk_get_rate(struct clk *clk);
> */
> void clk_put(struct clk *clk);
>
> -
> -/*
> - * The remaining APIs are optional for machine class support.
> - */
> -
> -
> /**
> * clk_round_rate - adjust a rate to the exact rate a clock can provide
> * @clk: clock source
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
[email protected] PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
Hi Ryan,
> > +int clk_enable(struct clk *clk)
> > +{
> > + int ret = 0;
> > +
> > + if (!clk->ops->enable)
> > + return 0;
> > +
> > + spin_lock(&clk->enable_lock);
>
> spin_lock_irqsave/spin_unlock_irqrestore. This could get called with
> irqs on or off.
Ah, I had planned to change this but (obviously) didn't get to it. Thanks for
the reminder, I'll include this in the next revision.
Cheers,
Jeremy
Hi Ryan,
> > +int clk_prepare(struct clk *clk)
> > +{
> > + int ret = 0;
> > +
> > + if (!clk->ops->prepare)
> > + return 0;
>
> If there is no ops->prepare function then we never increment
> prepare_count, which means that driver writers can get sloppy if they
> know that ops->prepare is no-op on their platform since they will not
> get warned for omitting clk_prepare.
Yeah, as discussed in other replies, it's probably best that we do the
counting unconditionally. I've removed these optimisations - I think we'd best
enforce the checking here, at least at the introduction of this API.
> Also, why are the warnings added in a separate patch rather than being
> rolled into this patch?
Just splitting things up; the warnings were the most discussed issue
previously, so I wanted to separate that discussion from the API side.
> Again, you should still increment enable_count even if ops->enabled is a
> no-op since it provides valuable warnings when clk_enable/disable calls
> are not matched correctly.
Yep, as above.
> > +unsigned long clk_get_rate(struct clk *clk)
> > +{
> > + if (clk->ops->get_rate)
> > + return clk->ops->get_rate(clk);
>
> Possibly we should shadow the clock rate if ops->get_rate is no-op? So
> clock initialisation and clk_set_rate store the rate in the shadow
> field, and then do:
>
> if (clk->ops->get_rate)
> return clk->ops->get_rate(clk);
> return clk->shadow_rate;
>
> Because the API is generic, driver writers should reasonably expect that
> clk_get_rate will return something valid without having to know the
> platform implementation details. It may also be worth having a warning
> to let the user know that the returned rate may be approximate.
I'd prefer to require that get_rate is implemented as an op, rather than
allowing two methods for retrieving the rate of the clock.
> > + return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(clk_get_rate);
> > +
> > +int __clk_get(struct clk *clk)
> > +{
> > + if (clk->ops->get)
> > + return clk->ops->get(clk);
> > + return 1;
> > +}
> > +EXPORT_SYMBOL_GPL(__clk_get);
> > +
> > +void clk_put(struct clk *clk)
> > +{
> > + if (clk->ops->put)
> > + clk->ops->put(clk);
> > +}
> > +EXPORT_SYMBOL_GPL(clk_put);
>
> This has probably been covered, and I have probably missed it, but why
> don't the generic clk_get/put functions do ref-counting? Drivers must
> have matched clk_get/put calls so it should work like enable/prepare
> counting right?
clk_get is used to find a clock; most implementations will not use this for
refcounting.
However, for the case where clocks are dynamically allocated, we need clk_put
to do any possible freeing. There's an existing API for this type of reference
counting (kref), so for the cases where this matters, the clock
implementations can use that.
> > + * The choice of atomic or non-atomic clock depends on how the clock is
> > enabled. + * Typically, you'll want to use a non-atomic clock. For
> > clocks that need to be + * enabled/disabled in interrupt context, use
> > CLK_ATOMIC. Note that atomic + * clocks with parents will typically
> > cascade enable/disable operations to + * their parent, so the parent of
> > an atomic clock *must* be atomic too.
>
> This comment seems out of date now that we have the prepare/enable
> semantics?
Yep, will update.
> > + * @unprepare: Release the clock from its prepared state. This will
> > typically + * undo any work done in the @prepare callback. Called
> > with + * clk->prepare_lock held.
>
> I think you need to make it more clear the prepare/unprepare must be
> called from a sleepable context.
The documentation on clk_ops is intended for the clock implementor, so it's
not really the right place to descibe the caller's requirements.
Indeed, the documentation for clk_prepare & clk_unprepare describe the
caller's requirements for these (and contain the words "This function may
sleep").
> > + * Typically, drivers will call clk_prepare when a clock may be needed
> > later + * (eg. when a device is opened), and clk_enable when the clock
> > is actually + * required (eg. from an interrupt).
>
> Drivers _must_ call clk_prepare before clk_enable (not typically)?
This 'typically' is about the actual placement of the clk_prepare and
clk_enable calls in the driver code, but I will clarify.
> > +/**
> > + * __clk_get - update clock-specific refcounter
> > + *
> > + * @clk: The clock to refcount
> > + *
> > + * Before a clock is returned from clk_get, this function should be
> > called + * to update any clock-specific refcounting.
> > + *
> > + * Returns non-zero on success, zero on failure.
> > + *
> > + * Drivers should not need this function; it is only needed by the
> > + * arch-specific clk_get() implementations.
> > + */
> > +int __clk_get(struct clk *clk);
>
> I don't understand this. Are architectures supposed to provide a
> function called clk_get? Doesn't this break the whole idea of having a
> common struct clk?
clk_get() is now provided in drivers/clk/clkdev.c; the arch-specific part of
this comment is old (I'll remove it).
Thanks for taking the time to review, I appreciate it.
Cheers,
Jeremy
On 02/08/2011 03:54 PM, Jeremy Kerr wrote:
> Hi Ryan,
>
>>> +unsigned long clk_get_rate(struct clk *clk)
>>> +{
>>> + if (clk->ops->get_rate)
>>> + return clk->ops->get_rate(clk);
>>
>> Possibly we should shadow the clock rate if ops->get_rate is no-op? So
>> clock initialisation and clk_set_rate store the rate in the shadow
>> field, and then do:
>>
>> if (clk->ops->get_rate)
>> return clk->ops->get_rate(clk);
>> return clk->shadow_rate;
>>
>> Because the API is generic, driver writers should reasonably expect that
>> clk_get_rate will return something valid without having to know the
>> platform implementation details. It may also be worth having a warning
>> to let the user know that the returned rate may be approximate.
>
> I'd prefer to require that get_rate is implemented as an op, rather than
> allowing two methods for retrieving the rate of the clock.
If a platform does not provide ops->get_rate and a driver writer does
not know this, they could naively use the 0 return from clk_get_rate in
calculations, which is especially bad if they ever divide by the rate.
At the very least the documentation for clk_get_rate should state that
the return value needs to be checked and that 0 means the rate is unknown.
>
>>> + return 0;
>>> +}
>>> +EXPORT_SYMBOL_GPL(clk_get_rate);
>>> +
>>> +int __clk_get(struct clk *clk)
>>> +{
>>> + if (clk->ops->get)
>>> + return clk->ops->get(clk);
>>> + return 1;
>>> +}
>>> +EXPORT_SYMBOL_GPL(__clk_get);
>>> +
>>> +void clk_put(struct clk *clk)
>>> +{
>>> + if (clk->ops->put)
>>> + clk->ops->put(clk);
>>> +}
>>> +EXPORT_SYMBOL_GPL(clk_put);
>>
>> This has probably been covered, and I have probably missed it, but why
>> don't the generic clk_get/put functions do ref-counting? Drivers must
>> have matched clk_get/put calls so it should work like enable/prepare
>> counting right?
>
> clk_get is used to find a clock; most implementations will not use this for
> refcounting.
>
> However, for the case where clocks are dynamically allocated, we need clk_put
> to do any possible freeing. There's an existing API for this type of reference
> counting (kref), so for the cases where this matters, the clock
> implementations can use that.
Ah, I see how the clkdev part fits in now. You are correct, the ref
counting is only needed/useful for dynamic allocation of clocks and
should therefore be done in the platform specific code.
We do currently have the slightly indirect route to getting a clock of
doing: clk_get -> __clk_get -> clk->ops->get. I'm guessing that the long
term goal is to remove the middle step once everything is using the
common clock api?
Also, how come you decided to keep the clk_get -> __clk_get call in
clkdev.c, but ifdef'ed clk_put? If you just leave clk_put as is in
clkdev.c and change clk_put to __clk_put in the generic clock code then
you need zero changes to clkdev.c
>
>>> + * The choice of atomic or non-atomic clock depends on how the clock is
>>> enabled. + * Typically, you'll want to use a non-atomic clock. For
>>> clocks that need to be + * enabled/disabled in interrupt context, use
>>> CLK_ATOMIC. Note that atomic + * clocks with parents will typically
>>> cascade enable/disable operations to + * their parent, so the parent of
>>> an atomic clock *must* be atomic too.
>>
>> This comment seems out of date now that we have the prepare/enable
>> semantics?
>
> Yep, will update.
>
>>> + * @unprepare: Release the clock from its prepared state. This will
>>> typically + * undo any work done in the @prepare callback. Called
>>> with + * clk->prepare_lock held.
>>
>> I think you need to make it more clear the prepare/unprepare must be
>> called from a sleepable context.
>
> The documentation on clk_ops is intended for the clock implementor, so it's
> not really the right place to descibe the caller's requirements.
>
> Indeed, the documentation for clk_prepare & clk_unprepare describe the
> caller's requirements for these (and contain the words "This function may
> sleep").
Okay. Should we document for the implementer that clk_enable/disable
must not sleep then? I don't think atomically is necessarily the right
word to use here. For example Documentation/serial/driver uses "This
call must not sleep".
~Ryan
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
[email protected] PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
Hi Ryan,
> If a platform does not provide ops->get_rate and a driver writer does
> not know this, they could naively use the 0 return from clk_get_rate in
> calculations, which is especially bad if they ever divide by the rate.
This would be fairly evident on first boot though :)
> At the very least the documentation for clk_get_rate should state that
> the return value needs to be checked and that 0 means the rate is unknown.
Yes, sounds good. I was hesitant to change the documentation for parts of the
API that are unchanged, but since we're formalising this 'return 0' behaviour,
it seems reasonable to update the comment in this case.
> We do currently have the slightly indirect route to getting a clock of
> doing: clk_get -> __clk_get -> clk->ops->get. I'm guessing that the long
> term goal is to remove the middle step once everything is using the
> common clock api?
That may never happen; I imagine that some platforms won't be converted at
all.
__clk_get has previously been used as a platform-specific hook to do
refcounting, which is exactly what we're doing here (via ops->get), so thought
it was best to use the existing __clk_get name to do this.
> Also, how come you decided to keep the clk_get -> __clk_get call in
> clkdev.c, but ifdef'ed clk_put? If you just leave clk_put as is in
> clkdev.c and change clk_put to __clk_put in the generic clock code then
> you need zero changes to clkdev.c
Yep, makes sense, I'll look at doing this.
> Okay. Should we document for the implementer that clk_enable/disable
> must not sleep then? I don't think atomically is necessarily the right
> word to use here. For example Documentation/serial/driver uses "This
> call must not sleep".
OK, I'll clarify the comment.
Cheers,
Jeremy
This change adds warnings to check for:
1) enabling a clock that hasn't been prepared; and
2) unpreparing a clock that is still enabled
While the correctness can't be guaranteed, the warnings should cover
most situations, and won't indicate false positives.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/clk.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index bbbdb0d..8c96623 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -29,6 +29,8 @@ EXPORT_SYMBOL_GPL(clk_prepare);
void clk_unprepare(struct clk *clk)
{
+ WARN_ON(clk->enable_count != 0);
+
mutex_lock(&clk->prepare_lock);
WARN_ON(clk->prepare_count == 0);
@@ -45,6 +47,8 @@ int clk_enable(struct clk *clk)
unsigned long flags;
int ret = 0;
+ WARN_ON(clk->prepare_count == 0);
+
spin_lock_irqsave(&clk->enable_lock, flags);
if (clk->enable_count == 0 && clk->ops->enable)
ret = clk->ops->enable(clk);
We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.
This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.
This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.
Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:
struct clk {
const struct clk_ops *ops;
unsigned int enable_count;
unsigned int prepare_count;
spinlock_t enable_lock;
struct mutex prepare_lock;
};
And a set of clock operations (defined per type of clock):
struct clk_ops {
int (*enable)(struct clk *);
void (*disable)(struct clk *);
unsigned long (*get_rate)(struct clk *);
[...]
};
To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:
struct clk_foo {
struct clk clk;
void __iomem *some_register;
};
struct clk_ops clk_foo_ops = {
.get_rate = clk_foo_get_rate,
};
The common clock definitions are based on a development patch from Ben
Herrenschmidt <[email protected]>.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/Kconfig | 3
drivers/clk/Makefile | 1
drivers/clk/clk.c | 126 +++++++++++++++++++++++++++
include/linux/clk.h | 194 +++++++++++++++++++++++++++++++++++++++++--
4 files changed, 315 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
config CLKDEV_LOOKUP
bool
select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+ bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..c35478a
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+ int ret = 0;
+
+ mutex_lock(&clk->prepare_lock);
+ if (clk->prepare_count == 0 && clk->ops->prepare)
+ ret = clk->ops->prepare(clk);
+
+ if (!ret)
+ clk->prepare_count++;
+ mutex_unlock(&clk->prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+ mutex_lock(&clk->prepare_lock);
+
+ WARN_ON(clk->prepare_count == 0);
+
+ if (--clk->prepare_count == 0 && clk->ops->unprepare)
+ clk->ops->unprepare(clk);
+
+ mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&clk->enable_lock, flags);
+ if (clk->enable_count == 0 && clk->ops->enable)
+ ret = clk->ops->enable(clk);
+
+ if (!ret)
+ clk->enable_count++;
+ spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clk->enable_lock, flags);
+
+ WARN_ON(clk->enable_count == 0);
+
+ if (!--clk->enable_count == 0 && clk->ops->disable)
+ clk->ops->disable(clk);
+
+ spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk->ops->get_rate)
+ return clk->ops->get_rate(clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->ops->round_rate)
+ return clk->ops->round_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->ops->set_rate)
+ return clk->ops->set_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (clk->ops->set_parent)
+ return clk->ops->set_parent(clk, parent);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (clk->ops->get_parent)
+ return clk->ops->get_parent(clk);
+ return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+ if (clk->ops->get)
+ return clk->ops->get(clk);
+ return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+ if (clk->ops->put)
+ clk->ops->put(clk);
+}
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..fe806b7 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
+ * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,198 @@
#ifndef __LINUX_CLK_H
#define __LINUX_CLK_H
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
struct device;
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops: implementation-specific ops for this clock
+ * @enable_count: count of clk_enable() calls active on this clock
+ * @enable_lock: lock for atomic enable
+ * @prepare_count: count of clk_prepare() calls active on this clock
+ * @prepare_lock: lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ * struct clk_foo {
+ * struct clk;
+ * [device specific fields]
+ * };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
+ */
+struct clk {
+ const struct clk_ops *ops;
+ unsigned int enable_count;
+ unsigned int prepare_count;
+ spinlock_t enable_lock;
+ struct mutex prepare_lock;
+};
+
+/* static initialiser for clocks */
+#define INIT_CLK(name, o) { \
+ .ops = &o, \
+ .enable_count = 0, \
+ .prepare_count = 0, \
+ .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
+ .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
+}
+
+/**
+ * struct clk_ops - Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare: Prepare the clock for enabling. This must not return until
+ * the clock is fully prepared, and it's safe to call clk_enable.
+ * This callback is intended to allow clock implementations to
+ * do any initialisation that may block. Called with
+ * clk->prepare_lock held.
+ *
+ * @unprepare: Release the clock from its prepared state. This will typically
+ * undo any work done in the @prepare callback. Called with
+ * clk->prepare_lock held.
+ *
+ * @enable: Enable the clock atomically. This must not return until the
+ * clock is generating a valid clock signal, usable by consumer
+ * devices. Called with clk->enable_lock held. This function
+ * must not sleep.
+ *
+ * @disable: Disable the clock atomically. Called with clk->enable_lock held.
+ * This function must not sleep.
+ *
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts. If a clock requires blocking code to be turned on, this
+ * should be done in clk_prepare. Switching that will not block should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see kernel/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+ int (*prepare)(struct clk *);
+ void (*unprepare)(struct clk *);
+ int (*enable)(struct clk *);
+ void (*disable)(struct clk *);
+ int (*get)(struct clk *);
+ void (*put)(struct clk *);
+ unsigned long (*get_rate)(struct clk *);
+ long (*round_rate)(struct clk *, unsigned long);
+ int (*set_rate)(struct clk *, unsigned long);
+ int (*set_parent)(struct clk *, struct clk *);
+ struct clk * (*get_parent)(struct clk *);
+};
+
+/**
+ * __clk_get - acquire a reference to a clock
+ *
+ * @clk: The clock to refcount
+ *
+ * Before a clock is returned from clk_get, this function should be called
+ * to update any clock-specific refcounting.
+ *
+ * Returns non-zero on success, zero on failure.
+ *
+ * Drivers should not need this function, it is called by the common clock
+ * infrastructure.
+ */
+int __clk_get(struct clk *clk);
+
+/**
+ * __clk_put - release reference to a clock
+ *
+ * @clk: The clock to release
+ *
+ * Called by clock infrastructure code to indicate that a clock consumer
+ * has released a clock, to update any clock-specific refcounting.
+ *
+ * Drivers should not need this function, it is called by the common clock
+ * infrastructure.
+ */
+void __clk_put(struct clk *clk);
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any blocking initialisation on @clk, allowing the clock to be later
+ * enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possbly blocking) cleanup on clk. This function may sleep.
*/
+void clk_unprepare(struct clk *clk);
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+ clk->enable_count = clk->prepare_count = 0;
+ spin_lock_init(&clk->enable_lock);
+ mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
*/
struct clk;
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+int clk_prepare(struct clk *clk) { return 0; }
+void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
/**
* clk_get - lookup and obtain a reference to a clock producer.
* @dev: device for clock "consumer"
@@ -67,6 +248,7 @@ void clk_disable(struct clk *clk);
/**
* clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
* This is only valid once the clock source has been enabled.
+ * Returns zero if the clock rate is unknown.
* @clk: clock source
*/
unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +265,6 @@ unsigned long clk_get_rate(struct clk *clk);
*/
void clk_put(struct clk *clk);
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
/**
* clk_round_rate - adjust a rate to the exact rate a clock can provide
* @clk: clock source
Hi all,
These patches are an attempt to allow platforms to share clock code. At
present, the definitions of 'struct clk' are local to platform code,
which makes allocating and initialising cross-platform clock sources
difficult, and makes it impossible to compile a single image containing
support for two ARM platforms with different struct clks.
The three patches are for the architecture-independent kernel code,
introducing the common clk infrastructure. The changelog for the first
patch includes details about the new clock definitions.
Ben Herrenschmidt is looking at using common struct clk code for powerpc
too, hence the kernel-wide approach.
Many thanks to the following for their input:
* Ben Dooks <[email protected]>
* Baruch Siach <[email protected]>
* Russell King <[email protected]>
* Uwe Kleine-König <[email protected]>
* Lorenzo Pieralisi <[email protected]>
* Vincent Guittot <[email protected]>
* Sascha Hauer <[email protected]>
* Ryan Mallon <[email protected]>
* Colin Cross <[email protected]>
* Jassi Brar <[email protected]>
Cheers,
Jeremy
--
v12:
* Always refcount, even when enable/prepare ops are NULL
* Unify prepare & enable count checking
* Update comments for prepare/unprepare
* Use spin_{lock,unlock}_irqsave
* Change clk_put to __clk_put, and use the shared clk_put
v11:
* add prepare/unprepare for non-atomic switching, document atomicity
* move to drivers/clk/
v10:
* comment fixups, from Uwe's review
* added DEFINE_CLK_FIXED
v9:
* comment improvements
* kerneldoc fixups
* add WARN_ON to clk_disable
v8:
* add atomic clocks, and locking wrappers
* expand comments on clk and clk_ops
v7:
* change CLK_INIT to initialise clk->mutex statically
v6:
* fixed up references to 'clk_operations' in the changelog
v5:
* uninline main API, and share definitions with !USE_COMMON_STRUCT_CLK
* add __clk_get
* delay mutex init
* kerneldoc for struct clk
v4:
* use mutex for enable/disable locking
* DEFINE_CLK -> INIT_CLK, and pass the clk name for mutex init
* struct clk_operations -> struct clk_ops
v3:
* do clock usage refcounting in common code
* provide sample port
v2:
* no longer ARM-specific
* use clk_operations
---
Jeremy Kerr (3):
Add a common struct clk
clk: Generic support for fixed-rate clocks
clk: add warnings for incorrect enable/prepare semantics
Since most platforms will need a fixed-rate clock, add one. This will
also serve as a basic example of an implementation of struct clk.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/clk.c | 14 ++++++++++++++
include/linux/clk.h | 16 ++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index c35478a..bbbdb0d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -124,3 +124,17 @@ void __clk_put(struct clk *clk)
if (clk->ops->put)
clk->ops->put(clk);
}
+
+/* clk_fixed support */
+
+#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
+
+static unsigned long clk_fixed_get_rate(struct clk *clk)
+{
+ return to_clk_fixed(clk)->rate;
+}
+
+struct clk_ops clk_fixed_ops = {
+ .get_rate = clk_fixed_get_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_ops);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index fe806b7..e67fdb0 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -185,6 +185,22 @@ static inline void clk_common_init(struct clk *clk)
mutex_init(&clk->prepare_lock);
}
+/* Simple fixed-rate clock */
+struct clk_fixed {
+ struct clk clk;
+ unsigned long rate;
+};
+
+extern struct clk_ops clk_fixed_ops;
+
+#define INIT_CLK_FIXED(name, r) { \
+ .clk = INIT_CLK(name.clk, clk_fixed_ops), \
+ .rate = (r) \
+}
+
+#define DEFINE_CLK_FIXED(name, r) \
+ struct clk_fixed name = INIT_CLK_FIXED(name, r)
+
#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
Hi, guys,
is there a documentation about clk framework?
Or only to read the sources?
Thanks a lot, and best regards
On Wednesday 09 February 2011 07:41:33 Jeremy Kerr wrote:
> Since most platforms will need a fixed-rate clock, add one. This will
> also serve as a basic example of an implementation of struct clk.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/clk.c | 14 ++++++++++++++
> include/linux/clk.h | 16 ++++++++++++++++
> 2 files changed, 30 insertions(+)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index c35478a..bbbdb0d 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -124,3 +124,17 @@ void __clk_put(struct clk *clk)
> if (clk->ops->put)
> clk->ops->put(clk);
> }
> +
> +/* clk_fixed support */
> +
> +#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
> +
> +static unsigned long clk_fixed_get_rate(struct clk *clk)
> +{
> + return to_clk_fixed(clk)->rate;
> +}
> +
> +struct clk_ops clk_fixed_ops = {
> + .get_rate = clk_fixed_get_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_fixed_ops);
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index fe806b7..e67fdb0 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -185,6 +185,22 @@ static inline void clk_common_init(struct clk *clk)
> mutex_init(&clk->prepare_lock);
> }
>
> +/* Simple fixed-rate clock */
> +struct clk_fixed {
> + struct clk clk;
> + unsigned long rate;
> +};
> +
> +extern struct clk_ops clk_fixed_ops;
> +
> +#define INIT_CLK_FIXED(name, r) { \
> + .clk = INIT_CLK(name.clk, clk_fixed_ops), \
> + .rate = (r) \
> +}
> +
> +#define DEFINE_CLK_FIXED(name, r) \
> + struct clk_fixed name = INIT_CLK_FIXED(name, r)
> +
> #else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>
> /*
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Ing. Fabio Giovagnini
Aurion s.r.l.
P.I e C.F.
00885711200
skype: aurion.giovagnini
Tel. +39.051.594.78.24
Fax. +39.051.082.14.49
Cell. +39.335.83.50.919
http://www.aurion-tech.com
Hi Jeremy,
On Wed, Feb 09, 2011 at 02:41:33PM +0800, Jeremy Kerr wrote:
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> const struct clk_ops *ops;
> unsigned int enable_count;
> unsigned int prepare_count;
> spinlock_t enable_lock;
> struct mutex prepare_lock;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_ops {
> int (*enable)(struct clk *);
> void (*disable)(struct clk *);
> unsigned long (*get_rate)(struct clk *);
> [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
> struct clk clk;
> void __iomem *some_register;
> };
>
> struct clk_ops clk_foo_ops = {
> .get_rate = clk_foo_get_rate,
> };
>
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <[email protected]>.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/Kconfig | 3
> drivers/clk/Makefile | 1
> drivers/clk/clk.c | 126 +++++++++++++++++++++++++++
> include/linux/clk.h | 194 +++++++++++++++++++++++++++++++++++++++++--
> 4 files changed, 315 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 4168c88..6e3ae54 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -2,3 +2,6 @@
> config CLKDEV_LOOKUP
> bool
> select HAVE_CLK
> +
> +config USE_COMMON_STRUCT_CLK
> + bool
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 07613fa..a1a06d3 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -1,2 +1,3 @@
>
> obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> new file mode 100644
> index 0000000..c35478a
> --- /dev/null
> +++ b/drivers/clk/clk.c
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +
> +int clk_prepare(struct clk *clk)
> +{
> + int ret = 0;
> +
> + mutex_lock(&clk->prepare_lock);
> + if (clk->prepare_count == 0 && clk->ops->prepare)
> + ret = clk->ops->prepare(clk);
> +
> + if (!ret)
> + clk->prepare_count++;
> + mutex_unlock(&clk->prepare_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_prepare);
> +
> +void clk_unprepare(struct clk *clk)
> +{
> + mutex_lock(&clk->prepare_lock);
> +
> + WARN_ON(clk->prepare_count == 0);
> +
> + if (--clk->prepare_count == 0 && clk->ops->unprepare)
> + clk->ops->unprepare(clk);
> +
> + mutex_unlock(&clk->prepare_lock);
> +}
> +EXPORT_SYMBOL_GPL(clk_unprepare);
> +
> +int clk_enable(struct clk *clk)
> +{
> + unsigned long flags;
> + int ret = 0;
> +
> + spin_lock_irqsave(&clk->enable_lock, flags);
> + if (clk->enable_count == 0 && clk->ops->enable)
> + ret = clk->ops->enable(clk);
> +
> + if (!ret)
> + clk->enable_count++;
> + spin_unlock_irqrestore(&clk->enable_lock, flags);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&clk->enable_lock, flags);
> +
> + WARN_ON(clk->enable_count == 0);
> +
> + if (!--clk->enable_count == 0 && clk->ops->disable)
s/!//
> + clk->ops->disable(clk);
> +
> + spin_unlock_irqrestore(&clk->enable_lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> + if (clk->ops->get_rate)
> + return clk->ops->get_rate(clk);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->round_rate)
> + return clk->ops->round_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->set_rate)
> + return clk->ops->set_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> + if (clk->ops->set_parent)
> + return clk->ops->set_parent(clk, parent);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> + if (clk->ops->get_parent)
> + return clk->ops->get_parent(clk);
> + return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
> +
> +int __clk_get(struct clk *clk)
> +{
> + if (clk->ops->get)
> + return clk->ops->get(clk);
> + return 1;
> +}
> +
> +void __clk_put(struct clk *clk)
> +{
> + if (clk->ops->put)
> + clk->ops->put(clk);
> +}
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..fe806b7 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
> *
> * Copyright (C) 2004 ARM Limited.
> * Written by Deep Blue Solutions Limited.
> + * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,198 @@
> #ifndef __LINUX_CLK_H
> #define __LINUX_CLK_H
>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +
> struct device;
>
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @ops: implementation-specific ops for this clock
> + * @enable_count: count of clk_enable() calls active on this clock
> + * @enable_lock: lock for atomic enable
> + * @prepare_count: count of clk_prepare() calls active on this clock
> + * @prepare_lock: lock for sleepable prepare
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + * struct clk_foo {
> + * struct clk;
> + * [device specific fields]
> + * };
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @enable_lock and @prepare_lock members are used to serialise accesses
> + * to the ops->enable and ops->prepare functions (and the corresponding
> + * ops->disable and ops->unprepare functions).
> + */
> +struct clk {
> + const struct clk_ops *ops;
> + unsigned int enable_count;
> + unsigned int prepare_count;
> + spinlock_t enable_lock;
> + struct mutex prepare_lock;
> +};
> +
> +/* static initialiser for clocks */
> +#define INIT_CLK(name, o) { \
> + .ops = &o, \
> + .enable_count = 0, \
> + .prepare_count = 0, \
> + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
> + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
> +}
> +
> +/**
> + * struct clk_ops - Callback operations for clocks; these are to be provided
> + * by the clock implementation, and will be called by drivers through the clk_*
> + * API.
> + *
> + * @prepare: Prepare the clock for enabling. This must not return until
> + * the clock is fully prepared, and it's safe to call clk_enable.
> + * This callback is intended to allow clock implementations to
> + * do any initialisation that may block. Called with
> + * clk->prepare_lock held.
> + *
> + * @unprepare: Release the clock from its prepared state. This will typically
> + * undo any work done in the @prepare callback. Called with
> + * clk->prepare_lock held.
> + *
> + * @enable: Enable the clock atomically. This must not return until the
> + * clock is generating a valid clock signal, usable by consumer
> + * devices. Called with clk->enable_lock held. This function
> + * must not sleep.
> + *
> + * @disable: Disable the clock atomically. Called with clk->enable_lock held.
> + * This function must not sleep.
> + *
> + * @get: Called by the core clock code when a device driver acquires a
> + * clock via clk_get(). Optional.
> + *
> + * @put: Called by the core clock code when a devices driver releases a
> + * clock via clk_put(). Optional.
> + *
> + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
> + * implementations to split any work between atomic (enable) and sleepable
> + * (prepare) contexts. If a clock requires blocking code to be turned on, this
> + * should be done in clk_prepare. Switching that will not block should be done
> + * in clk_enable.
> + *
> + * Typically, drivers will call clk_prepare when a clock may be needed later
> + * (eg. when a device is opened), and clk_enable when the clock is actually
> + * required (eg. from an interrupt). Note that clk_prepare *must* have been
> + * called before clk_enable.
> + *
> + * For other callbacks, see the corresponding clk_* functions. Parameters and
> + * return values are passed directly from/to these API functions, or
> + * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
> + * is NULL, see kernel/clk.c for implementation details. All are optional.
> + */
> +struct clk_ops {
> + int (*prepare)(struct clk *);
> + void (*unprepare)(struct clk *);
> + int (*enable)(struct clk *);
> + void (*disable)(struct clk *);
> + int (*get)(struct clk *);
> + void (*put)(struct clk *);
> + unsigned long (*get_rate)(struct clk *);
> + long (*round_rate)(struct clk *, unsigned long);
> + int (*set_rate)(struct clk *, unsigned long);
> + int (*set_parent)(struct clk *, struct clk *);
> + struct clk * (*get_parent)(struct clk *);
> +};
> +
> +/**
> + * __clk_get - acquire a reference to a clock
> + *
> + * @clk: The clock to refcount
> + *
> + * Before a clock is returned from clk_get, this function should be called
> + * to update any clock-specific refcounting.
> + *
> + * Returns non-zero on success, zero on failure.
> + *
> + * Drivers should not need this function, it is called by the common clock
> + * infrastructure.
> + */
> +int __clk_get(struct clk *clk);
> +
> +/**
> + * __clk_put - release reference to a clock
> + *
> + * @clk: The clock to release
> + *
> + * Called by clock infrastructure code to indicate that a clock consumer
> + * has released a clock, to update any clock-specific refcounting.
> + *
> + * Drivers should not need this function, it is called by the common clock
> + * infrastructure.
> + */
> +void __clk_put(struct clk *clk);
> +
> +/**
> + * clk_prepare - prepare clock for atomic enabling.
> + *
> + * @clk: The clock to prepare
> + *
> + * Do any blocking initialisation on @clk, allowing the clock to be later
> + * enabled atomically (via clk_enable). This function may sleep.
> + */
> +int clk_prepare(struct clk *clk);
> +
> +/**
> + * clk_unprepare - release clock from prepared state
> + *
> + * @clk: The clock to release
> + *
> + * Do any (possbly blocking) cleanup on clk. This function may sleep.
s/possbly/possibly/
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On 02/09/2011 07:41 PM, Jeremy Kerr wrote:
Hi Jeremy,
Couple more comments below.
~Ryan
> We currently have ~21 definitions of struct clk in the ARM architecture,
> each defined on a per-platform basis. This makes it difficult to define
> platform- (or architecture-) independent clock sources without making
> assumptions about struct clk, and impossible to compile two
> platforms with different struct clks into a single image.
>
> This change is an effort to unify struct clk where possible, by defining
> a common struct clk, containing a set of clock operations. Different
> clock implementations can set their own operations, and have a standard
> interface for generic code. The callback interface is exposed to the
> kernel proper, while the clock implementations only need to be seen by
> the platform internals.
>
> This allows us to share clock code among platforms, and makes it
> possible to dynamically create clock devices in platform-independent
> code.
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> const struct clk_ops *ops;
> unsigned int enable_count;
> unsigned int prepare_count;
> spinlock_t enable_lock;
> struct mutex prepare_lock;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_ops {
> int (*enable)(struct clk *);
> void (*disable)(struct clk *);
> unsigned long (*get_rate)(struct clk *);
> [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
> struct clk clk;
> void __iomem *some_register;
> };
>
> struct clk_ops clk_foo_ops = {
> .get_rate = clk_foo_get_rate,
> };
>
> The common clock definitions are based on a development patch from Ben
> Herrenschmidt <[email protected]>.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/Kconfig | 3
> drivers/clk/Makefile | 1
> drivers/clk/clk.c | 126 +++++++++++++++++++++++++++
> include/linux/clk.h | 194 +++++++++++++++++++++++++++++++++++++++++--
> 4 files changed, 315 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 4168c88..6e3ae54 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -2,3 +2,6 @@
> config CLKDEV_LOOKUP
> bool
> select HAVE_CLK
> +
> +config USE_COMMON_STRUCT_CLK
> + bool
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 07613fa..a1a06d3 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -1,2 +1,3 @@
>
> obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
> +obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> new file mode 100644
> index 0000000..c35478a
> --- /dev/null
> +++ b/drivers/clk/clk.c
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Standard functionality for the common clock API.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +
> +int clk_prepare(struct clk *clk)
> +{
> + int ret = 0;
> +
> + mutex_lock(&clk->prepare_lock);
> + if (clk->prepare_count == 0 && clk->ops->prepare)
> + ret = clk->ops->prepare(clk);
> +
> + if (!ret)
> + clk->prepare_count++;
> + mutex_unlock(&clk->prepare_lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_prepare);
> +
> +void clk_unprepare(struct clk *clk)
> +{
> + mutex_lock(&clk->prepare_lock);
> +
> + WARN_ON(clk->prepare_count == 0);
> +
> + if (--clk->prepare_count == 0 && clk->ops->unprepare)
> + clk->ops->unprepare(clk);
> +
> + mutex_unlock(&clk->prepare_lock);
> +}
> +EXPORT_SYMBOL_GPL(clk_unprepare);
> +
> +int clk_enable(struct clk *clk)
> +{
> + unsigned long flags;
> + int ret = 0;
> +
> + spin_lock_irqsave(&clk->enable_lock, flags);
WARN_ON(clk->prepare_count == 0); ?
> + if (clk->enable_count == 0 && clk->ops->enable)
> + ret = clk->ops->enable(clk);
Does it make sense to have a clock with no enable function which still
returns success from clk_enable? Do we have any platforms which have
NULL clk_enable functions?
I think that for enable/disable at least we should require platforms to
provide functions and oops if they have failed to do so. In the rare
case that a platform doesn't need to do anything for enable/disable they
can just supply empty functions.
> +
> + if (!ret)
> + clk->enable_count++;
> + spin_unlock_irqrestore(&clk->enable_lock, flags);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(clk_enable);
> +
> +void clk_disable(struct clk *clk)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&clk->enable_lock, flags);
> +
> + WARN_ON(clk->enable_count == 0);
> +
> + if (!--clk->enable_count == 0 && clk->ops->disable)
> + clk->ops->disable(clk);
> +
> + spin_unlock_irqrestore(&clk->enable_lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(clk_disable);
> +
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> + if (clk->ops->get_rate)
> + return clk->ops->get_rate(clk);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(clk_get_rate);
> +
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->round_rate)
> + return clk->ops->round_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_round_rate);
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + if (clk->ops->set_rate)
> + return clk->ops->set_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> + if (clk->ops->set_parent)
> + return clk->ops->set_parent(clk, parent);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> + if (clk->ops->get_parent)
> + return clk->ops->get_parent(clk);
> + return ERR_PTR(-ENOSYS);
> +}
> +EXPORT_SYMBOL_GPL(clk_get_parent);
> +
> +int __clk_get(struct clk *clk)
> +{
> + if (clk->ops->get)
> + return clk->ops->get(clk);
> + return 1;
> +}
> +
> +void __clk_put(struct clk *clk)
> +{
> + if (clk->ops->put)
> + clk->ops->put(clk);
> +}
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..fe806b7 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
> *
> * Copyright (C) 2004 ARM Limited.
> * Written by Deep Blue Solutions Limited.
> + * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> @@ -11,18 +12,198 @@
> #ifndef __LINUX_CLK_H
> #define __LINUX_CLK_H
>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/spinlock.h>
> +
> struct device;
>
> -/*
> - * The base API.
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> +
> +/* If we're using the common struct clk, we define the base clk object here */
> +
> +/**
> + * struct clk - hardware independent clock structure
> + * @ops: implementation-specific ops for this clock
> + * @enable_count: count of clk_enable() calls active on this clock
> + * @enable_lock: lock for atomic enable
> + * @prepare_count: count of clk_prepare() calls active on this clock
> + * @prepare_lock: lock for sleepable prepare
> + *
> + * The base clock object, used by drivers for hardware-independent manipulation
> + * of clock lines. This will be 'subclassed' by device-specific implementations,
> + * which add device-specific data to struct clk. For example:
> + *
> + * struct clk_foo {
> + * struct clk;
> + * [device specific fields]
> + * };
> + *
> + * The clock driver code will manage the device-specific data, and pass
> + * clk_foo.clk to the common clock code. The clock driver will be called
> + * through the @ops callbacks.
> + *
> + * The @enable_lock and @prepare_lock members are used to serialise accesses
> + * to the ops->enable and ops->prepare functions (and the corresponding
> + * ops->disable and ops->unprepare functions).
> + */
> +struct clk {
> + const struct clk_ops *ops;
> + unsigned int enable_count;
> + unsigned int prepare_count;
> + spinlock_t enable_lock;
> + struct mutex prepare_lock;
> +};
> +
> +/* static initialiser for clocks */
> +#define INIT_CLK(name, o) { \
> + .ops = &o, \
> + .enable_count = 0, \
> + .prepare_count = 0, \
> + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
> + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
> +}
> +
> +/**
> + * struct clk_ops - Callback operations for clocks; these are to be provided
> + * by the clock implementation, and will be called by drivers through the clk_*
> + * API.
> + *
> + * @prepare: Prepare the clock for enabling. This must not return until
> + * the clock is fully prepared, and it's safe to call clk_enable.
> + * This callback is intended to allow clock implementations to
> + * do any initialisation that may block. Called with
> + * clk->prepare_lock held.
> + *
> + * @unprepare: Release the clock from its prepared state. This will typically
> + * undo any work done in the @prepare callback. Called with
> + * clk->prepare_lock held.
> + *
> + * @enable: Enable the clock atomically. This must not return until the
> + * clock is generating a valid clock signal, usable by consumer
> + * devices. Called with clk->enable_lock held. This function
> + * must not sleep.
> + *
> + * @disable: Disable the clock atomically. Called with clk->enable_lock held.
> + * This function must not sleep.
> + *
> + * @get: Called by the core clock code when a device driver acquires a
> + * clock via clk_get(). Optional.
> + *
> + * @put: Called by the core clock code when a devices driver releases a
> + * clock via clk_put(). Optional.
> + *
> + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
> + * implementations to split any work between atomic (enable) and sleepable
> + * (prepare) contexts. If a clock requires blocking code to be turned on, this
> + * should be done in clk_prepare. Switching that will not block should be done
> + * in clk_enable.
> + *
> + * Typically, drivers will call clk_prepare when a clock may be needed later
> + * (eg. when a device is opened), and clk_enable when the clock is actually
> + * required (eg. from an interrupt). Note that clk_prepare *must* have been
> + * called before clk_enable.
> + *
> + * For other callbacks, see the corresponding clk_* functions. Parameters and
> + * return values are passed directly from/to these API functions, or
> + * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
> + * is NULL, see kernel/clk.c for implementation details. All are optional.
> + */
> +struct clk_ops {
> + int (*prepare)(struct clk *);
> + void (*unprepare)(struct clk *);
> + int (*enable)(struct clk *);
> + void (*disable)(struct clk *);
> + int (*get)(struct clk *);
> + void (*put)(struct clk *);
> + unsigned long (*get_rate)(struct clk *);
> + long (*round_rate)(struct clk *, unsigned long);
> + int (*set_rate)(struct clk *, unsigned long);
> + int (*set_parent)(struct clk *, struct clk *);
> + struct clk * (*get_parent)(struct clk *);
> +};
> +
> +/**
> + * __clk_get - acquire a reference to a clock
> + *
> + * @clk: The clock to refcount
> + *
> + * Before a clock is returned from clk_get, this function should be called
> + * to update any clock-specific refcounting.
This is a bit misleading. It's not "should be called", it "is called". I
think you should just remove the documentation for __clk_get/__clk_put
or move it into clk.c since the functions are only used internally by
the common clock code.
> + *
> + * Returns non-zero on success, zero on failure.
> + *
> + * Drivers should not need this function, it is called by the common clock
> + * infrastructure.
> + */
> +int __clk_get(struct clk *clk);
> +
> +/**
> + * __clk_put - release reference to a clock
> + *
> + * @clk: The clock to release
> + *
> + * Called by clock infrastructure code to indicate that a clock consumer
> + * has released a clock, to update any clock-specific refcounting.
> + *
> + * Drivers should not need this function, it is called by the common clock
> + * infrastructure.
> + */
> +void __clk_put(struct clk *clk);
> +
> +/**
> + * clk_prepare - prepare clock for atomic enabling.
> + *
> + * @clk: The clock to prepare
> + *
> + * Do any blocking initialisation on @clk, allowing the clock to be later
> + * enabled atomically (via clk_enable). This function may sleep.
"Possibly blocking" as below?
> + */
> +int clk_prepare(struct clk *clk);
> +
> +/**
> + * clk_unprepare - release clock from prepared state
> + *
> + * @clk: The clock to release
> + *
> + * Do any (possbly blocking) cleanup on clk. This function may sleep.
Typo "possbly".
> */
> +void clk_unprepare(struct clk *clk);
>
> +/**
> + * clk_common_init - initialise a clock for driver usage
> + *
> + * @clk: The clock to initialise
> + *
> + * Used for runtime intialization of clocks; you don't need to call this
> + * if your clock has been (statically) initialized with INIT_CLK.
> + */
> +static inline void clk_common_init(struct clk *clk)
> +{
> + clk->enable_count = clk->prepare_count = 0;
> + spin_lock_init(&clk->enable_lock);
> + mutex_init(&clk->prepare_lock);
> +}
> +
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>
> /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
> */
> struct clk;
>
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +/*
> + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> + * functions are no-ops
> + */
> +int clk_prepare(struct clk *clk) { return 0; }
> +void clk_unprepare(struct clk *clk) { }
> +
> +#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
> +
> /**
> * clk_get - lookup and obtain a reference to a clock producer.
> * @dev: device for clock "consumer"
> @@ -67,6 +248,7 @@ void clk_disable(struct clk *clk);
> /**
> * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
> * This is only valid once the clock source has been enabled.
> + * Returns zero if the clock rate is unknown.
> * @clk: clock source
> */
> unsigned long clk_get_rate(struct clk *clk);
> @@ -83,12 +265,6 @@ unsigned long clk_get_rate(struct clk *clk);
> */
> void clk_put(struct clk *clk);
>
> -
> -/*
> - * The remaining APIs are optional for machine class support.
> - */
> -
> -
> /**
> * clk_round_rate - adjust a rate to the exact rate a clock can provide
> * @clk: clock source
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
[email protected] PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
Hi Ryan,
On Thu, Feb 10, 2011 at 09:21:14AM +1300, Ryan Mallon wrote:
> > +int clk_enable(struct clk *clk)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + spin_lock_irqsave(&clk->enable_lock, flags);
>
> WARN_ON(clk->prepare_count == 0); ?
This is added in patch 3/3
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On 02/10/2011 09:39 AM, Uwe Kleine-K?nig wrote:
> Hi Ryan,
>
> On Thu, Feb 10, 2011 at 09:21:14AM +1300, Ryan Mallon wrote:
>>> +int clk_enable(struct clk *clk)
>>> +{
>>> + unsigned long flags;
>>> + int ret = 0;
>>> +
>>> + spin_lock_irqsave(&clk->enable_lock, flags);
>>
>> WARN_ON(clk->prepare_count == 0); ?
> This is added in patch 3/3
Ah, missed that. I still think that patch 3 should just be rolled into
patch 1. I don't see why we should add a new file in one patch and then
randomly add some warning code to it in another patch. It makes
reviewing harder for one thing :-).
~Ryan
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
[email protected] PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
On 02/07/2011 06:24 AM, Nicolas Pitre wrote:
> On Mon, 7 Feb 2011, Jeremy Kerr wrote:
>
>> Hi Uwe,
>>
>>> This implies the warning is only issued on clocks that have a prepare
>>> callback. If we want to enforce the new API the warning here shouldn't
>>> depend on clk->ops->prepare. (clk_prepare and clk_unprepare need to
>>> be changed then to adapt the prepare_count even in the absence of
>>> clk->ops->prepare.)
>>
>> Yeah, it's a decision about either adding a small cost to all clk_prepare()s
>> (ie, adding cost when there is no prepare callback), or checking for the
>> correct prepare/enable semantics for all clocks (even when it doesn't matter
>> for that particular clock). I chose the first as more important, but happy to
>> go either way here.
>
> The prepare method being called from non-atomic context cannot be
> considered to be in a speed critical path. Most of the time, this is
> going to be called on driver initialization or the like, and that's a
> relatively rare event. Therefore this really small cost to clk_prepare()
> is definitively worth it to help proper usage of the API. If this ever
> becomes a problem then this could be confined to some CONFIG_CLK_DEBUG
> or the like. But when introducing a new API it is best to be more
> strict to help people get its usage right (without going overboard with
> it of course).
>
Agree with Nicholas and Uwe. +1 for this request.
-Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On 02/08/2011 10:41 PM, Jeremy Kerr wrote:
[snip]
> +
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
Shouldn't you be grabbing the prepare_lock here? Set rate and
prepare/unprepare would be working on the same shared resource (say,
PLL). That was the reason we are making set_rate() sleepable too.
As a nice side effect, it will also enforce the "might sleep" nature of
this API.
You should probably rename the lock to something else since it's not
limited to prepare/unprepare. How about resource_lock?
> + if (clk->ops->set_rate)
> + return clk->ops->set_rate(clk, rate);
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_rate);
> +
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> + if (clk->ops->set_parent)
> + return clk->ops->set_parent(clk, parent);
I'm not sure on this one. If the prepare ops for a clock also calls the
prepare ops on the parent, shouldn't we prevent changing the parent
while the prepare/unprepare is going on?
> + return -ENOSYS;
> +}
> +EXPORT_SYMBOL_GPL(clk_set_parent);
> +
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..fe806b7 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -3,6 +3,7 @@
[snip]
> +
> +/* static initialiser for clocks */
> +#define INIT_CLK(name, o) { \
> + .ops =&o, \
> + .enable_count = 0, \
> + .prepare_count = 0, \
Do we need these inits? Doesn't check patch complain about initing
static/global to 0? If it's generally frowned upon, why the exception
here. I realize that checkpatch won't catch this, but still...
> + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
> + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
After a long day, I'm not able to wrap my head around this. Probably a
stupid question, but will this name.xxx thing prevent using this
INIT_CLK macro to initialize an array of clocks? More specifically,
prevent the sub class macro (like INIT_CLK_FIXED) from being used to
initialize an array of clocks?
> +}
> +
> +/**
> + * struct clk_ops - Callback operations for clocks; these are to be provided
> + * by the clock implementation, and will be called by drivers through the clk_*
> + * API.
> + *
> + * @prepare: Prepare the clock for enabling. This must not return until
> + * the clock is fully prepared, and it's safe to call clk_enable.
> + * This callback is intended to allow clock implementations to
> + * do any initialisation that may block. Called with
> + * clk->prepare_lock held.
> + *
> + * @unprepare: Release the clock from its prepared state. This will typically
> + * undo any work done in the @prepare callback. Called with
> + * clk->prepare_lock held.
> + *
> + * @enable: Enable the clock atomically. This must not return until the
> + * clock is generating a valid clock signal, usable by consumer
> + * devices. Called with clk->enable_lock held. This function
> + * must not sleep.
> + *
> + * @disable: Disable the clock atomically. Called with clk->enable_lock held.
> + * This function must not sleep.
> + *
> + * @get: Called by the core clock code when a device driver acquires a
> + * clock via clk_get(). Optional.
> + *
> + * @put: Called by the core clock code when a devices driver releases a
> + * clock via clk_put(). Optional.
> + *
> + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
> + * implementations to split any work between atomic (enable) and sleepable
> + * (prepare) contexts. If a clock requires blocking code to be turned on, this
Aren't all locks blocking? Shouldn't it be, "If turning on a clock
requires code that might sleep, it should be done in clk_prepare"?
Replace all "blocking" with "sleepable" or "sleeping" in the comments?
> + * should be done in clk_prepare. Switching that will not block should be done
> + * in clk_enable.
> + *
> + * Typically, drivers will call clk_prepare when a clock may be needed later
> + * (eg. when a device is opened), and clk_enable when the clock is actually
> + * required (eg. from an interrupt). Note that clk_prepare *must* have been
> + * called before clk_enable.
> + *
> + * For other callbacks, see the corresponding clk_* functions. Parameters and
> + * return values are passed directly from/to these API functions, or
> + * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
> + * is NULL, see kernel/clk.c for implementation details. All are optional.
is NULL. See kernel... ?
> + */
> +struct clk_ops {
> + int (*prepare)(struct clk *);
> + void (*unprepare)(struct clk *);
> + int (*enable)(struct clk *);
> + void (*disable)(struct clk *);
> + int (*get)(struct clk *);
> + void (*put)(struct clk *);
> + unsigned long (*get_rate)(struct clk *);
> + long (*round_rate)(struct clk *, unsigned long);
> + int (*set_rate)(struct clk *, unsigned long);
> + int (*set_parent)(struct clk *, struct clk *);
> + struct clk * (*get_parent)(struct clk *);
> +};
> +
Thanks,
Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Hi Jeremy,
On Wed, Feb 09, 2011 at 02:41:33PM +0800, Jeremy Kerr wrote:
> This change adds warnings to check for:
>
> 1) enabling a clock that hasn't been prepared; and
>
> 2) unpreparing a clock that is still enabled
>
> While the correctness can't be guaranteed, the warnings should cover
> most situations, and won't indicate false positives.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/clk.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index bbbdb0d..8c96623 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -29,6 +29,8 @@ EXPORT_SYMBOL_GPL(clk_prepare);
>
> void clk_unprepare(struct clk *clk)
> {
> + WARN_ON(clk->enable_count != 0);
> +
Other drivers may be using the clock and increased the enable_count.
This check may be moved to where we actually do unprepare.
Thanks
Richard
> mutex_lock(&clk->prepare_lock);
>
> WARN_ON(clk->prepare_count == 0);
> @@ -45,6 +47,8 @@ int clk_enable(struct clk *clk)
> unsigned long flags;
> int ret = 0;
>
> + WARN_ON(clk->prepare_count == 0);
> +
> spin_lock_irqsave(&clk->enable_lock, flags);
> if (clk->enable_count == 0 && clk->ops->enable)
> ret = clk->ops->enable(clk);
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
On Thu, Feb 10, 2011 at 09:21:14AM +1300, Ryan Mallon wrote:
> On 02/09/2011 07:41 PM, Jeremy Kerr wrote:
>
> Hi Jeremy,
>
> Couple more comments below.
>
> ~Ryan
>
[...]
> > +int clk_enable(struct clk *clk)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + spin_lock_irqsave(&clk->enable_lock, flags);
>
> WARN_ON(clk->prepare_count == 0); ?
>
> > + if (clk->enable_count == 0 && clk->ops->enable)
> > + ret = clk->ops->enable(clk);
>
> Does it make sense to have a clock with no enable function which still
> returns success from clk_enable? Do we have any platforms which have
> NULL clk_enable functions?
>
> I think that for enable/disable at least we should require platforms to
> provide functions and oops if they have failed to do so. In the rare
> case that a platform doesn't need to do anything for enable/disable they
> can just supply empty functions.
It's possible to be NULL. So are set_rate/get_rate.
Ideally, if it's NULL:
prepare/unprepare: only call parent's prepare/unprepare
enable/disable: only call parent's enable/disable
set_rate: fail
get_rate: reture parent's get_rate
set_parent: fail
get_parent: fail
Thanks
Richard
>
> > +
> > + if (!ret)
> > + clk->enable_count++;
> > + spin_unlock_irqrestore(&clk->enable_lock, flags);
> > +
> > + return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(clk_enable);
> > +
On 10/02/11 23:03, Richard Zhao wrote:
> On Thu, Feb 10, 2011 at 09:21:14AM +1300, Ryan Mallon wrote:
>> On 02/09/2011 07:41 PM, Jeremy Kerr wrote:
>>
>> Hi Jeremy,
>>
>> Couple more comments below.
>>
>> ~Ryan
>>
> [...]
>>> +int clk_enable(struct clk *clk)
>>> +{
>>> + unsigned long flags;
>>> + int ret = 0;
>>> +
>>> + spin_lock_irqsave(&clk->enable_lock, flags);
>> WARN_ON(clk->prepare_count == 0); ?
>>
>>> + if (clk->enable_count == 0&& clk->ops->enable)
>>> + ret = clk->ops->enable(clk);
>> Does it make sense to have a clock with no enable function which still
>> returns success from clk_enable? Do we have any platforms which have
>> NULL clk_enable functions?
>>
>> I think that for enable/disable at least we should require platforms to
>> provide functions and oops if they have failed to do so. In the rare
>> case that a platform doesn't need to do anything for enable/disable they
>> can just supply empty functions.
> It's possible to be NULL. So are set_rate/get_rate.
> Ideally, if it's NULL:
> prepare/unprepare: only call parent's prepare/unprepare
> enable/disable: only call parent's enable/disable
No, the whole point of the generic framework is that _all_ clock users
must call prepare/enable and disable/unprepare. Drivers, etc should not
rely on underlying knowledge of a platform. This is why, for instance,
clk_enable will warn if prepare count is zero.
However, I can see that a clock may be fully enabled by its prepare
function and so the enable function is a no-op. User must still call
both prepare and enable though. Perhaps this is what you meant?
~Ryan
Hello,
On Thu, Feb 10, 2011 at 06:03:19PM +0800, Richard Zhao wrote:
> On Thu, Feb 10, 2011 at 09:21:14AM +1300, Ryan Mallon wrote:
> > On 02/09/2011 07:41 PM, Jeremy Kerr wrote:
> >
> > Hi Jeremy,
> >
> > Couple more comments below.
> >
> > ~Ryan
> >
> [...]
> > > +int clk_enable(struct clk *clk)
> > > +{
> > > + unsigned long flags;
> > > + int ret = 0;
> > > +
> > > + spin_lock_irqsave(&clk->enable_lock, flags);
> >
> > WARN_ON(clk->prepare_count == 0); ?
> >
> > > + if (clk->enable_count == 0 && clk->ops->enable)
> > > + ret = clk->ops->enable(clk);
> >
> > Does it make sense to have a clock with no enable function which still
> > returns success from clk_enable? Do we have any platforms which have
> > NULL clk_enable functions?
> >
> > I think that for enable/disable at least we should require platforms to
> > provide functions and oops if they have failed to do so. In the rare
> > case that a platform doesn't need to do anything for enable/disable they
> > can just supply empty functions.
> It's possible to be NULL. So are set_rate/get_rate.
> Ideally, if it's NULL:
> prepare/unprepare: only call parent's prepare/unprepare
> enable/disable: only call parent's enable/disable
> set_rate: fail
> get_rate: reture parent's get_rate
> set_parent: fail
> get_parent: fail
I wouldn't hard-code the parents into the generic functions. But I
suggest to provide generic callbacks to do this, e.g.
clk_get_rate_from_parent(struct clk *c)
{
struct clk *parent = clk_get_parent(c);
return clk_get_rate(parent);
}
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Thu, Feb 10, 2011 at 11:10:52PM +1300, Ryan Mallon wrote:
> On 10/02/11 23:03, Richard Zhao wrote:
> >On Thu, Feb 10, 2011 at 09:21:14AM +1300, Ryan Mallon wrote:
> >>On 02/09/2011 07:41 PM, Jeremy Kerr wrote:
> >>
> >>Hi Jeremy,
> >>
> >>Couple more comments below.
> >>
> >>~Ryan
> >>
> >[...]
> >>>+int clk_enable(struct clk *clk)
> >>>+{
> >>>+ unsigned long flags;
> >>>+ int ret = 0;
> >>>+
> >>>+ spin_lock_irqsave(&clk->enable_lock, flags);
> >> WARN_ON(clk->prepare_count == 0); ?
> >>
> >>>+ if (clk->enable_count == 0&& clk->ops->enable)
> >>>+ ret = clk->ops->enable(clk);
> >>Does it make sense to have a clock with no enable function which still
> >>returns success from clk_enable? Do we have any platforms which have
> >>NULL clk_enable functions?
> >>
> >>I think that for enable/disable at least we should require platforms to
> >>provide functions and oops if they have failed to do so. In the rare
> >>case that a platform doesn't need to do anything for enable/disable they
> >>can just supply empty functions.
> >It's possible to be NULL. So are set_rate/get_rate.
> >Ideally, if it's NULL:
> >prepare/unprepare: only call parent's prepare/unprepare
> >enable/disable: only call parent's enable/disable
>
> No, the whole point of the generic framework is that _all_ clock
> users must call prepare/enable and disable/unprepare. Drivers, etc
> should not rely on underlying knowledge of a platform. This is why,
> for instance, clk_enable will warn if prepare count is zero.
>
> However, I can see that a clock may be fully enabled by its prepare
> function and so the enable function is a no-op. User must still call
> both prepare and enable though. Perhaps this is what you meant?
I mean prepare/unprepare, enable/disable and get_rate ops null can be handled
in the common clock code. But it needs parent clock pointer.
Thanks
Richard
>
> ~Ryan
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Feb 10, 2011 at 11:46:39AM +0100, Uwe Kleine-K?nig wrote:
> Hello,
>
> On Thu, Feb 10, 2011 at 06:03:19PM +0800, Richard Zhao wrote:
> > On Thu, Feb 10, 2011 at 09:21:14AM +1300, Ryan Mallon wrote:
> > > On 02/09/2011 07:41 PM, Jeremy Kerr wrote:
> > >
> > > Hi Jeremy,
> > >
> > > Couple more comments below.
> > >
> > > ~Ryan
> > >
> > [...]
> > > > +int clk_enable(struct clk *clk)
> > > > +{
> > > > + unsigned long flags;
> > > > + int ret = 0;
> > > > +
> > > > + spin_lock_irqsave(&clk->enable_lock, flags);
> > >
> > > WARN_ON(clk->prepare_count == 0); ?
> > >
> > > > + if (clk->enable_count == 0 && clk->ops->enable)
> > > > + ret = clk->ops->enable(clk);
> > >
> > > Does it make sense to have a clock with no enable function which still
> > > returns success from clk_enable? Do we have any platforms which have
> > > NULL clk_enable functions?
> > >
> > > I think that for enable/disable at least we should require platforms to
> > > provide functions and oops if they have failed to do so. In the rare
> > > case that a platform doesn't need to do anything for enable/disable they
> > > can just supply empty functions.
> > It's possible to be NULL. So are set_rate/get_rate.
> > Ideally, if it's NULL:
> > prepare/unprepare: only call parent's prepare/unprepare
> > enable/disable: only call parent's enable/disable
> > set_rate: fail
> > get_rate: reture parent's get_rate
> > set_parent: fail
> > get_parent: fail
> I wouldn't hard-code the parents into the generic functions. But I
> suggest to provide generic callbacks to do this, e.g.
Why? what restriction will it cause to add parent in clk?
Two benifits at least I can see:
1. null ops handle, as I said above.
2. export clock tree to user level for debug. It's very helpfull.
Thanks
Richard
>
> clk_get_rate_from_parent(struct clk *c)
> {
> struct clk *parent = clk_get_parent(c);
>
> return clk_get_rate(parent);
> }
>
> Best regards
> Uwe
>
> --
> Pengutronix e.K. | Uwe Kleine-K?nig |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Feb 10, 2011 at 09:08:00PM +0800, Richard Zhao wrote:
> Why? what restriction will it cause to add parent in clk?
> Two benifits at least I can see:
> 1. null ops handle, as I said above.
> 2. export clock tree to user level for debug. It's very helpfull.
Don't be tempted to expand what's done at the generic level. Platforms
may need special handling at the current clock level before the parent
clock level is considered. Also platforms may not have parents so it
becomes mere bloat.
The more complicated the generic level becomes, the more platforms won't
covert to it.
On 02/09/2011 07:41 PM, Jeremy Kerr wrote:
> Since most platforms will need a fixed-rate clock, add one. This will
> also serve as a basic example of an implementation of struct clk.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/clk.c | 14 ++++++++++++++
> include/linux/clk.h | 16 ++++++++++++++++
> 2 files changed, 30 insertions(+)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index c35478a..bbbdb0d 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -124,3 +124,17 @@ void __clk_put(struct clk *clk)
> if (clk->ops->put)
> clk->ops->put(clk);
> }
> +
> +/* clk_fixed support */
> +
> +#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
> +
> +static unsigned long clk_fixed_get_rate(struct clk *clk)
> +{
> + return to_clk_fixed(clk)->rate;
> +}
> +
> +struct clk_ops clk_fixed_ops = {
> + .get_rate = clk_fixed_get_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_fixed_ops);
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index fe806b7..e67fdb0 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -185,6 +185,22 @@ static inline void clk_common_init(struct clk *clk)
> mutex_init(&clk->prepare_lock);
> }
>
> +/* Simple fixed-rate clock */
> +struct clk_fixed {
> + struct clk clk;
> + unsigned long rate;
> +};
> +
> +extern struct clk_ops clk_fixed_ops;
> +
> +#define INIT_CLK_FIXED(name, r) { \
> + .clk = INIT_CLK(name.clk, clk_fixed_ops), \
> + .rate = (r) \
> +}
A fixed clock may still have other operations such as enable/disable.
Maybe do something like this instead:
#define INIT_CLK_FIXED(name, ops, r) { \
.clk = INIT_CLK(name.clk, ops, rate), \
.clk.ops.get_rate = clk_fixed_get_rate, \
.rate = (r), \
}
That's untested though. I'm not sure if you can reliably assign
something twice in a struct initialiser?
~Ryan
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
[email protected] PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
Hi Ryan,
> > +int clk_enable(struct clk *clk)
> > +{
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + spin_lock_irqsave(&clk->enable_lock, flags);
>
> WARN_ON(clk->prepare_count == 0); ?
Added later, but yes.
>
> > + if (clk->enable_count == 0 && clk->ops->enable)
> > + ret = clk->ops->enable(clk);
>
> Does it make sense to have a clock with no enable function which still
> returns success from clk_enable? Do we have any platforms which have
> NULL clk_enable functions?
It does, yes. Driver code should be always be calling clk_enable before using
a clock, regardless of the implementation (which it shouldn't have to care
abut), and should abort their initialisation if the clk_enable() fails.
Some clocks are always running, so the enable op will be empty. This is not an
error, so the driver is free to continue.
> I think that for enable/disable at least we should require platforms to
> provide functions and oops if they have failed to do so. In the rare
> case that a platform doesn't need to do anything for enable/disable they
> can just supply empty functions.
Sounds like useless boilerplate - it's not an error to not need
enable/disable, so I don't see why we need to add extra effort to handle this
case.
> > +/**
> > + * __clk_get - acquire a reference to a clock
> > + *
> > + * @clk: The clock to refcount
> > + *
> > + * Before a clock is returned from clk_get, this function should be
> > called + * to update any clock-specific refcounting.
>
> This is a bit misleading. It's not "should be called", it "is called". I
> think you should just remove the documentation for __clk_get/__clk_put
> or move it into clk.c since the functions are only used internally by
> the common clock code.
It'd be nice to remove this from the header, but this means we'll need extern
prototypes in clkdev.c. Might be a reasonable compromise though.
> > +/**
> > + * clk_prepare - prepare clock for atomic enabling.
> > + *
> > + * @clk: The clock to prepare
> > + *
> > + * Do any blocking initialisation on @clk, allowing the clock to be
> > later + * enabled atomically (via clk_enable). This function may sleep.
>
> "Possibly blocking" as below?
Yep, will unify these (and spell "possibly" correctly :) )
Cheers,
Jeremy
Hi Ryan,
> A fixed clock may still have other operations such as enable/disable.
Then it's not a fixed clock; I'd prefer this to be a separate type, as it's
now hardware dependent.
> Maybe do something like this instead:
> #define INIT_CLK_FIXED(name, ops, r) { \
> .clk = INIT_CLK(name.clk, ops, rate), \
> .clk.ops.get_rate = clk_fixed_get_rate, \
> .rate = (r), \
> }
>
> That's untested though. I'm not sure if you can reliably assign
> something twice in a struct initialiser?
also, clk->ops is a const.
Cheers,
Jeremy
On 02/15/2011 02:36 PM, Jeremy Kerr wrote:
> Hi Ryan,
>
>>> +int clk_enable(struct clk *clk)
>>> +{
>>> + unsigned long flags;
>>> + int ret = 0;
>>> +
>>> + spin_lock_irqsave(&clk->enable_lock, flags);
>>
>> WARN_ON(clk->prepare_count == 0); ?
>
> Added later, but yes.
Okay, but still failing to understand why this isn't it the first patch.
You are introducing a new file after all.
>>
>>> + if (clk->enable_count == 0 && clk->ops->enable)
>>> + ret = clk->ops->enable(clk);
>>
>> Does it make sense to have a clock with no enable function which still
>> returns success from clk_enable? Do we have any platforms which have
>> NULL clk_enable functions?
>
> It does, yes. Driver code should be always be calling clk_enable before using
> a clock, regardless of the implementation (which it shouldn't have to care
> abut), and should abort their initialisation if the clk_enable() fails.
>
> Some clocks are always running, so the enable op will be empty. This is not an
> error, so the driver is free to continue.
>
>> I think that for enable/disable at least we should require platforms to
>> provide functions and oops if they have failed to do so. In the rare
>> case that a platform doesn't need to do anything for enable/disable they
>> can just supply empty functions.
>
> Sounds like useless boilerplate - it's not an error to not need
> enable/disable, so I don't see why we need to add extra effort to handle this
> case.
I have been convinced that enable/prepare potentially being NULL
callbacks is valid :-).
>
>>> +/**
>>> + * __clk_get - acquire a reference to a clock
>>> + *
>>> + * @clk: The clock to refcount
>>> + *
>>> + * Before a clock is returned from clk_get, this function should be
>>> called + * to update any clock-specific refcounting.
>>
>> This is a bit misleading. It's not "should be called", it "is called". I
>> think you should just remove the documentation for __clk_get/__clk_put
>> or move it into clk.c since the functions are only used internally by
>> the common clock code.
>
> It'd be nice to remove this from the header, but this means we'll need extern
> prototypes in clkdev.c. Might be a reasonable compromise though.
That's probably a better approach anyway, since that makes it blatantly
obvious that the __clk_get and __clk_put functions should not be called
from anywhere except clkdev.c.
>
>>> +/**
>>> + * clk_prepare - prepare clock for atomic enabling.
>>> + *
>>> + * @clk: The clock to prepare
>>> + *
>>> + * Do any blocking initialisation on @clk, allowing the clock to be
>>> later + * enabled atomically (via clk_enable). This function may sleep.
>>
>> "Possibly blocking" as below?
>
> Yep, will unify these (and spell "possibly" correctly :) )
:-)
~Ryan
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
[email protected] PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
Hi Richard,
> > void clk_unprepare(struct clk *clk)
> > {
> >
> > + WARN_ON(clk->enable_count != 0);
> > +
>
> Other drivers may be using the clock and increased the enable_count.
> This check may be moved to where we actually do unprepare.
Of course, thanks. Will update the series.
Jeremy
Hi Saravana,
> Shouldn't you be grabbing the prepare_lock here?
This depends on semantics that (as far as I can tell) aren't defined yet. We
may even want to disallow set_rate (and set_parent) when prepare_count is non-
zero.
Ideally, we should work out what the semantics are with regards to changing a
clock's rate when it has multiple users and/or is enabled or prepared, but
that's a separate issue, and we should *definitely* implement that as a
separate change.
I'd prefer to enforce the 'sleepability' with might_sleep instead.
> You should probably rename the lock to something else since it's not
> limited to prepare/unprepare. How about resource_lock?
It's not, but that's the only thing it's protecting in the common code. I'm
open for better names, but resource_lock is too generic.
> > +int clk_set_parent(struct clk *clk, struct clk *parent)
> > +{
> > + if (clk->ops->set_parent)
> > + return clk->ops->set_parent(clk, parent);
>
> I'm not sure on this one. If the prepare ops for a clock also calls the
> prepare ops on the parent, shouldn't we prevent changing the parent
> while the prepare/unprepare is going on?
Again, this is related to set_rate during enable/disable or prepare/unprepare;
we don't have defined semantics for this at present.
> > +
> > +/* static initialiser for clocks */
> > +#define INIT_CLK(name, o) { \
> > + .ops =&o, \
> > + .enable_count = 0, \
> > + .prepare_count = 0, \
>
> Do we need these inits? Doesn't check patch complain about initing
> static/global to 0? If it's generally frowned upon, why the exception
> here. I realize that checkpatch won't catch this, but still...
This took some reading through c99, but yes, it looks like we can drop these
zero initialisations.
However, the coding style convention for the implicit zeroing of static
variables is to allow these variables to be put into the .bss section,
reducing object size. In this case, the clock will never be able to go into
.bss (it has non-zero elements too), and so this will have no change on object
size. I prefer to be explicit here, and show that the counts are initialised
to zero.
I'm happy to go either way. I have a preference for the explicit
initialisation, but that may not be general style.
>
> > + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
> > + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
>
> After a long day, I'm not able to wrap my head around this. Probably a
> stupid question, but will this name.xxx thing prevent using this
> INIT_CLK macro to initialize an array of clocks? More specifically,
> prevent the sub class macro (like INIT_CLK_FIXED) from being used to
> initialize an array of clocks?
That's correct. For an array of clocks, you'll have to use a different
initialiser. We can add helpers for that that when (and if) the need arises.
> > + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
> > + * implementations to split any work between atomic (enable) and
> > sleepable + * (prepare) contexts. If a clock requires blocking code to
> > be turned on, this
>
> Aren't all locks blocking? Shouldn't it be, "If turning on a clock
> requires code that might sleep, it should be done in clk_prepare"?
> Replace all "blocking" with "sleepable" or "sleeping" in the comments?
I think "blocking" is generally accepted as is intended in this case, but it's
probably better to be explicit here.
>
> > + * should be done in clk_prepare. Switching that will not block should
> > be done + * in clk_enable.
> > + *
> > + * Typically, drivers will call clk_prepare when a clock may be needed
> > later + * (eg. when a device is opened), and clk_enable when the clock
> > is actually + * required (eg. from an interrupt). Note that clk_prepare
> > *must* have been + * called before clk_enable.
> > + *
> > + * For other callbacks, see the corresponding clk_* functions.
> > Parameters and + * return values are passed directly from/to these API
> > functions, or + * -ENOSYS (or zero, in the case of clk_get_rate) is
> > returned if the callback + * is NULL, see kernel/clk.c for
> > implementation details. All are optional.
>
> is NULL. See kernel... ?
Ah, yes, I'll update this.
Cheers,
Jeremy
On 02/14/2011 05:41 PM, Jeremy Kerr wrote:
> Hi Ryan,
>
>> A fixed clock may still have other operations such as enable/disable.
>
> Then it's not a fixed clock; I'd prefer this to be a separate type, as it's
> now hardware dependent.
>
I'm confused. If a clock's rate can't be changed and it can't be enabled
or disabled, then what's the point of representing that clock
signal/line as a clock in the driver. Seems like a "nothing to see here,
move along" type of clock. To express it differently, I find this
similar to "if (1) { ... }". Obviously I'm missing something here. What
is it?
-Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Russell, A question for you further down this email. Please take a look.
On 02/14/2011 06:41 PM, Jeremy Kerr wrote:
> Hi Saravana,
>
>> Shouldn't you be grabbing the prepare_lock here?
>
> This depends on semantics that (as far as I can tell) aren't defined yet.
Sure, one could argue that in some archs for a certain set of clocks the
slow stuff in prepare/unprepare won't need to be done during set rate --
say, a simple clock that always runs off the same PLL but just has a
integer divider to change the rate.
In those cases, not grabbing the prepare_lock would make the code less
"locky".
> We
> may even want to disallow set_rate (and set_parent) when prepare_count is non-
> zero.
This is definitely not right. Changing the rate of a clock when it's
already enabled/prepared is a very reasonable thing to do. It's only
doing a set rate at the "same time" as a prepare/unprepare that's wrong
for some clocks. We could have the specific implementation deal with the
locking internally.
So essentially, the prepare_lock is just for the prepare_cnt and the
call to the corresponding ops.
> Ideally, we should work out what the semantics are with regards to changing a
> clock's rate when it has multiple users and/or is enabled or prepared, but
> that's a separate issue, and we should *definitely* implement that as a
> separate change.
Agreed about having the semantics defined for setting the rate when
there are multiple users. As for "is already enabled/prepared", I think
clear that it needs to be supported/allowed. MSM drivers definitely do
it all the time.
> I'd prefer to enforce the 'sleepability' with might_sleep instead.
Yeah, I realized this option after sending out my previous email. Please
do add a might_sleep(). It will actually point out errors (per the new
clarification) in some serial drivers.
>> You should probably rename the lock to something else since it's not
>> limited to prepare/unprepare. How about resource_lock?
>
> It's not, but that's the only thing it's protecting in the common code. I'm
> open for better names, but resource_lock is too generic.
We can get back to this later after we settle on the stuff below.
>>> +int clk_set_parent(struct clk *clk, struct clk *parent)
>>> +{
>>> + if (clk->ops->set_parent)
>>> + return clk->ops->set_parent(clk, parent);
>>
>> I'm not sure on this one. If the prepare ops for a clock also calls the
>> prepare ops on the parent, shouldn't we prevent changing the parent
>> while the prepare/unprepare is going on?
>
> Again, this is related to set_rate during enable/disable or prepare/unprepare;
> we don't have defined semantics for this at present.
After thinking about this the past couple of days, this looks like a
location where the locking is more necessary than inside set rate. I
always saw the parent clock as the clock that generates the clock signal
from which this clock derives (divide, etc) it's clock signal from.
Assuming Russell and/or the community agrees on the semantics of
"parent", without the generic implementation grabbing the prepare_lock
while setting the parent, there is no way for the specific clock driver
implementations to cleanly ensure correctness. The only option for them
would be to peek into the generic clock struct and grab the prepare lock
-- to me that would be an ugly hack and/or layering violation that would
cause problems later on.
Russell/All,
What's the meaning of a parent clock? Do you agree with my definition --
"the parent clock is the clock that generates the clock signal from
which the child clock derives (divide, etc) it's clock signal from."? Or
is it open to interpretation by each implementation?
>>> +
>>> +/* static initialiser for clocks */
>>> +#define INIT_CLK(name, o) { \
>>> + .ops =&o, \
>>> + .enable_count = 0, \
>>> + .prepare_count = 0, \
>>
>> Do we need these inits? Doesn't check patch complain about initing
>> static/global to 0? If it's generally frowned upon, why the exception
>> here. I realize that checkpatch won't catch this, but still...
>
> This took some reading through c99, but yes, it looks like we can drop these
> zero initialisations.
>
> However, the coding style convention for the implicit zeroing of static
> variables is to allow these variables to be put into the .bss section,
> reducing object size. In this case, the clock will never be able to go into
> .bss (it has non-zero elements too), and so this will have no change on object
> size. I prefer to be explicit here, and show that the counts are initialised
> to zero.
I don't think the coding style convention was to make sure the variables
end up in the BSS. I would be surprised if GCC wasn't intelligent enough
to notice that we are initing a variable with zero and hence it can be
safely put in the BSS. It think the coding style convention was chosen
just to ensure "don't be redundant and add 'noisy' code".
> I'm happy to go either way. I have a preference for the explicit
> initialisation, but that may not be general style.
I don't have a strong opinion, but I thought I should point out the
deviation from the usual coding style.
>>
>>> + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
>>> + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
>>
>> After a long day, I'm not able to wrap my head around this. Probably a
>> stupid question, but will this name.xxx thing prevent using this
>> INIT_CLK macro to initialize an array of clocks? More specifically,
>> prevent the sub class macro (like INIT_CLK_FIXED) from being used to
>> initialize an array of clocks?
>
> That's correct. For an array of clocks, you'll have to use a different
> initialiser. We can add helpers for that that when (and if) the need arises.
Would it even be possible to get this to work for an array? You don't
have to change this in the patch, but I'm curious to know how to get
this to work for an array without doing a run time init of the lock.
>>> + * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
>>> + * implementations to split any work between atomic (enable) and
>>> sleepable + * (prepare) contexts. If a clock requires blocking code to
>>> be turned on, this
>>
>> Aren't all locks blocking? Shouldn't it be, "If turning on a clock
>> requires code that might sleep, it should be done in clk_prepare"?
>> Replace all "blocking" with "sleepable" or "sleeping" in the comments?
>
> I think "blocking" is generally accepted as is intended in this case, but it's
> probably better to be explicit here.
I obviously think what I suggested is clearer, but no strong opinion here.
Cheers,
Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Hi Saravana,
> >> A fixed clock may still have other operations such as enable/disable.
> >
> > Then it's not a fixed clock; I'd prefer this to be a separate type, as
> > it's now hardware dependent.
>
> I'm confused. If a clock's rate can't be changed and it can't be enabled
> or disabled, then what's the point of representing that clock
> signal/line as a clock in the driver.
Because the drivers using this clock don't know that it's a fixed clock.
For example, a uart needs to know the rate of its clock source, so that it can
set its internal divisors to get a valid baud rate. The uart driver will query
the input rate using clk_get_rate(). The driver still needs to call
clk_enable/clk_prepare/etc, because on some systems it may have a switchable
clock.
Cheers,
Jeremy
On 02/14/2011 10:18 PM, Jeremy Kerr wrote:
> Because the drivers using this clock don't know that it's a fixed clock.
>
> For example, a uart needs to know the rate of its clock source, so that it can
> set its internal divisors to get a valid baud rate. The uart driver will query
> the input rate using clk_get_rate(). The driver still needs to call
> clk_enable/clk_prepare/etc, because on some systems it may have a switchable
> clock.
Thanks. Makes sense.
-Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Hi Saravana,
> Sure, one could argue that in some archs for a certain set of clocks the
> slow stuff in prepare/unprepare won't need to be done during set rate --
> say, a simple clock that always runs off the same PLL but just has a
> integer divider to change the rate.
>
> In those cases, not grabbing the prepare_lock would make the code less
> "locky".
>
> > We
> > may even want to disallow set_rate (and set_parent) when prepare_count is
> > non- zero.
>
> This is definitely not right.
Why is that? Consider two devices using one clock; one does some
initialisation based on the return value of clk_get_rate(), the other calls
clk_set_rate() some time later. Now the first device is incorrectly
initialised.
Regardless, this is definitely something to flag for a later discussion. I'm
happy to return to that, but we should focus on one issue at a time here.
> Changing the rate of a clock when it's
> already enabled/prepared is a very reasonable thing to do. It's only
> doing a set rate at the "same time" as a prepare/unprepare that's wrong
> for some clocks. We could have the specific implementation deal with the
> locking internally.
Yes, hence leaving the locking here to the clock implementation.
> > I'd prefer to enforce the 'sleepability' with might_sleep instead.
>
> Yeah, I realized this option after sending out my previous email. Please
> do add a might_sleep(). It will actually point out errors (per the new
> clarification) in some serial drivers.
Yep, will do.
> >>> + .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
> >>> + .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
> >>
> >> After a long day, I'm not able to wrap my head around this. Probably a
> >> stupid question, but will this name.xxx thing prevent using this
> >> INIT_CLK macro to initialize an array of clocks? More specifically,
> >> prevent the sub class macro (like INIT_CLK_FIXED) from being used to
> >> initialize an array of clocks?
> >
> > That's correct. For an array of clocks, you'll have to use a different
> > initialiser. We can add helpers for that that when (and if) the need
> > arises.
>
> Would it even be possible to get this to work for an array? You don't
> have to change this in the patch, but I'm curious to know how to get
> this to work for an array without doing a run time init of the lock.
I'd assume that you'd have to do this at run time, as with any other array of
structs that contain a mutex or spinlock.
Cheers,
Jeremy
Hi Jeremy,
Sorry, if the formatting is weird. Using webmail client
On Mon, February 14, 2011 11:26 pm, Jeremy Kerr wrote:
>> > We
>> > may even want to disallow set_rate (and set_parent) when prepare_count
>> is
>> > non- zero.
>>
>> This is definitely not right.
>
> Why is that? Consider two devices using one clock; one does some
> initialisation based on the return value of clk_get_rate(), the other
> calls
> clk_set_rate() some time later. Now the first device is incorrectly
> initialised.
The case you describe is certainly something I consider as incorrect and
agree with you in that we should try to prevent it. But
(prepare_count != 0) != (two devices using one clock).
For one, prepare_count == 1 would be a normal case when a clock is enabled
and the MSM drivers certainly want to be able to set the rate when the
clock is enabled.
But (prepare_count > 1 || enable_count > 1) doesn't mean more than one
device/device driver using the clock either. A simple example would be a
driver wrapping all it's register accesses with a clk_enable/clk_disable
and not having to worry about if a clock is enabled during register access
when it has multiple execution paths (threads, interrupt handler, timers,
etc) that access registers. The driver would just do the enable/disable
around register accesses and let the clock code's ref counting dealing
with making sure a clock is never turned off when it's needed. In these
case both the prepare_count (less likely, but likely) and enable_count can
greater than 1.
Long story short, I support your desire to prevent one driver from
changing the rate from underneath another driver, but the condition you
chose to figure that out is not accurate.
> Regardless, this is definitely something to flag for a later discussion.
> I'm
> happy to return to that, but we should focus on one issue at a time here.
Sure, this discussion of set rate with count is non-zero can be reserved
for later. But I think the discussion of grabbing the lock during
set_parent should be discussed in the context of this patch.
Waiting to see how others feel about this.
Thanks,
Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Tue, Feb 15, 2011 at 03:26:53PM +0800, Jeremy Kerr wrote:
> Hi Saravana,
>
> > Sure, one could argue that in some archs for a certain set of clocks the
> > slow stuff in prepare/unprepare won't need to be done during set rate --
> > say, a simple clock that always runs off the same PLL but just has a
> > integer divider to change the rate.
> >
> > In those cases, not grabbing the prepare_lock would make the code less
> > "locky".
> >
> > > We
> > > may even want to disallow set_rate (and set_parent) when prepare_count is
> > > non- zero.
> >
> > This is definitely not right.
>
> Why is that? Consider two devices using one clock; one does some
> initialisation based on the return value of clk_get_rate(), the other calls
> clk_set_rate() some time later. Now the first device is incorrectly
> initialised.
What about a clock sourced from a PLL which provides the dotclock for a
framebuffer device? On every mode set, should the clk have to be disabled,
unprepared, rate set, re-prepared and re-enabled?
Hi Russell,
> > Why is that? Consider two devices using one clock; one does some
> > initialisation based on the return value of clk_get_rate(), the other
> > calls clk_set_rate() some time later. Now the first device is
> > incorrectly initialised.
>
> What about a clock sourced from a PLL which provides the dotclock for a
> framebuffer device? On every mode set, should the clk have to be disabled,
> unprepared, rate set, re-prepared and re-enabled?
Sounds heavy-handed, but I honestly have no idea if that's reasonable or not.
Other options are:
* Require that the driver has called clk_prepare, and that prepare_count
is 1 during the set_rate call (indicating that this is the only user); or
* Leave the set_rate and set_parent semantics as-is and assume that anything
calling either knows what it's doing (and that it won't affect other
devices)
Are you OK if we address this separately to the API unification though?
Cheers,
Jeremy
On Tue, Feb 15, 2011 at 05:33:29PM +0800, Jeremy Kerr wrote:
> Hi Russell,
>
> > > Why is that? Consider two devices using one clock; one does some
> > > initialisation based on the return value of clk_get_rate(), the other
> > > calls clk_set_rate() some time later. Now the first device is
> > > incorrectly initialised.
> >
> > What about a clock sourced from a PLL which provides the dotclock for a
> > framebuffer device? On every mode set, should the clk have to be disabled,
> > unprepared, rate set, re-prepared and re-enabled?
>
> Sounds heavy-handed, but I honestly have no idea if that's reasonable or not.
>
> Other options are:
>
> * Require that the driver has called clk_prepare, and that prepare_count
> is 1 during the set_rate call (indicating that this is the only user); or
>
> * Leave the set_rate and set_parent semantics as-is and assume that anything
> calling either knows what it's doing (and that it won't affect other
> devices)
I vote the second option. Two reasons:
1. Has any mach specific clock restricted clk_set_rate use? I don't hear any.
2. In my opinion, clk_set_rate is not called very often by drivers, especially
for the clock which has child clocks. Leaf clock are seldom shared. Even if it's
shared, we can let drivers handle it case by case .
Thanks
Richard
>
> Are you OK if we address this separately to the API unification though?
>
> Cheers,
>
>
> Jeremy
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On 02/14/2011 09:33 PM, Saravana Kannan wrote:
> Russell, A question for you further down this email. Please take a look.
Russell, Ping... I will snip the rest of the discussion so that it's
easy to spot the question.
>>>> +int clk_set_parent(struct clk *clk, struct clk *parent)
>>>> +{
>>>> + if (clk->ops->set_parent)
>>>> + return clk->ops->set_parent(clk, parent);
>>>
>>> I'm not sure on this one. If the prepare ops for a clock also calls the
>>> prepare ops on the parent, shouldn't we prevent changing the parent
>>> while the prepare/unprepare is going on?
>>
>> Again, this is related to set_rate during enable/disable or
>> prepare/unprepare;
>> we don't have defined semantics for this at present.
>
> After thinking about this the past couple of days, this looks like a
> location where the locking is more necessary than inside set rate. I
> always saw the parent clock as the clock that generates the clock signal
> from which this clock derives (divide, etc) it's clock signal from.
>
> Assuming Russell and/or the community agrees on the semantics of
> "parent", without the generic implementation grabbing the prepare_lock
> while setting the parent, there is no way for the specific clock driver
> implementations to cleanly ensure correctness. The only option for them
> would be to peek into the generic clock struct and grab the prepare lock
> -- to me that would be an ugly hack and/or layering violation that would
> cause problems later on.
>
> Russell/All,
>
> What's the meaning of a parent clock? Do you agree with my definition --
> "the parent clock is the clock that generates the clock signal from
> which the child clock derives (divide, etc) it's clock signal from."? Or
> is it open to interpretation by each implementation?
Thanks,
Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Tue, Feb 15, 2011 at 05:33:29PM +0800, Jeremy Kerr wrote:
> Hi Russell,
>
> > > Why is that? Consider two devices using one clock; one does some
> > > initialisation based on the return value of clk_get_rate(), the other
> > > calls clk_set_rate() some time later. Now the first device is
> > > incorrectly initialised.
> >
> > What about a clock sourced from a PLL which provides the dotclock for a
> > framebuffer device? On every mode set, should the clk have to be disabled,
> > unprepared, rate set, re-prepared and re-enabled?
>
> Sounds heavy-handed, but I honestly have no idea if that's reasonable or not.
>
> Other options are:
>
> * Require that the driver has called clk_prepare, and that prepare_count
> is 1 during the set_rate call (indicating that this is the only user); or
>
> * Leave the set_rate and set_parent semantics as-is and assume that anything
> calling either knows what it's doing (and that it won't affect other
> devices)
>
> Are you OK if we address this separately to the API unification though?
Absolutely. I think there's enough issues already without adding new
changes on top. The unification step should do just that - unify. It
should not introduce new restrictions that are not absolutely necessary
for the unification step.
On Mon, Feb 14, 2011 at 09:33:03PM -0800, Saravana Kannan wrote:
> Assuming Russell and/or the community agrees on the semantics of
> "parent", without the generic implementation grabbing the prepare_lock
> while setting the parent, there is no way for the specific clock driver
> implementations to cleanly ensure correctness. The only option for them
> would be to peek into the generic clock struct and grab the prepare lock
> -- to me that would be an ugly hack and/or layering violation that would
> cause problems later on.
>
> Russell/All,
>
> What's the meaning of a parent clock? Do you agree with my definition --
> "the parent clock is the clock that generates the clock signal from
> which the child clock derives (divide, etc) it's clock signal from."? Or
> is it open to interpretation by each implementation?
Your definition seems sane - I'm not sure what use a parent clock which
had nothing to do with a child would be.
As for the locking issue, I've no idea on that at the moment. I don't
think implementations should grab the prepare lock, I think that's
something the generic code should take care of for clk_set_rate(),
clk_set_parent() etc.
We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.
This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.
This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.
Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:
struct clk {
const struct clk_ops *ops;
unsigned int enable_count;
unsigned int prepare_count;
spinlock_t enable_lock;
struct mutex prepare_lock;
};
And a set of clock operations (defined per type of clock):
struct clk_ops {
int (*enable)(struct clk *);
void (*disable)(struct clk *);
unsigned long (*get_rate)(struct clk *);
[...]
};
To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:
struct clk_foo {
struct clk clk;
void __iomem *some_register;
};
struct clk_ops clk_foo_ops = {
.get_rate = clk_foo_get_rate,
};
The common clock definitions are based on a development patch from Ben
Herrenschmidt <[email protected]>.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/Kconfig | 3
drivers/clk/Makefile | 1
drivers/clk/clk.c | 132 ++++++++++++++++++++++++++++++++++
drivers/clk/clkdev.c | 7 +
include/linux/clk.h | 164 ++++++++++++++++++++++++++++++++++++++++---
5 files changed, 298 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
config CLKDEV_LOOKUP
bool
select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+ bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+ int ret = 0;
+
+ mutex_lock(&clk->prepare_lock);
+ if (clk->prepare_count == 0 && clk->ops->prepare)
+ ret = clk->ops->prepare(clk);
+
+ if (!ret)
+ clk->prepare_count++;
+ mutex_unlock(&clk->prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+ mutex_lock(&clk->prepare_lock);
+
+ WARN_ON(clk->prepare_count == 0);
+
+ if (--clk->prepare_count == 0 && clk->ops->unprepare) {
+ WARN_ON(clk->enable_count != 0);
+ clk->ops->unprepare(clk);
+ }
+
+ mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ WARN_ON(clk->prepare_count == 0);
+
+ spin_lock_irqsave(&clk->enable_lock, flags);
+ if (clk->enable_count == 0 && clk->ops->enable)
+ ret = clk->ops->enable(clk);
+
+ if (!ret)
+ clk->enable_count++;
+ spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clk->enable_lock, flags);
+
+ WARN_ON(clk->enable_count == 0);
+
+ if (!--clk->enable_count == 0 && clk->ops->disable)
+ clk->ops->disable(clk);
+
+ spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk->ops->get_rate)
+ return clk->ops->get_rate(clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->ops->round_rate)
+ return clk->ops->round_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ might_sleep();
+
+ if (clk->ops->set_rate)
+ return clk->ops->set_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (clk->ops->set_parent)
+ return clk->ops->set_parent(clk, parent);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (clk->ops->get_parent)
+ return clk->ops->get_parent(clk);
+ return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+ if (clk->ops->get)
+ return clk->ops->get(clk);
+ return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+ if (clk->ops->put)
+ clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
/*
* Find the correct struct clk for the device and connection ID.
* We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..604be74 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
+ * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
#ifndef __LINUX_CLK_H
#define __LINUX_CLK_H
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
struct device;
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops: implementation-specific ops for this clock
+ * @enable_count: count of clk_enable() calls active on this clock
+ * @enable_lock: lock for atomic enable
+ * @prepare_count: count of clk_prepare() calls active on this clock
+ * @prepare_lock: lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ * struct clk_foo {
+ * struct clk;
+ * [device specific fields]
+ * };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
*/
+struct clk {
+ const struct clk_ops *ops;
+ unsigned int enable_count;
+ unsigned int prepare_count;
+ spinlock_t enable_lock;
+ struct mutex prepare_lock;
+};
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) { \
+ .ops = &o, \
+ .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
+ .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
+}
+
+/**
+ * struct clk_ops - Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare: Prepare the clock for enabling. This must not return until
+ * the clock is fully prepared, and it's safe to call clk_enable.
+ * This callback is intended to allow clock implementations to
+ * do any initialisation that may sleep. Called with
+ * clk->prepare_lock held.
+ *
+ * @unprepare: Release the clock from its prepared state. This will typically
+ * undo any work done in the @prepare callback. Called with
+ * clk->prepare_lock held.
+ *
+ * @enable: Enable the clock atomically. This must not return until the
+ * clock is generating a valid clock signal, usable by consumer
+ * devices. Called with clk->enable_lock held. This function
+ * must not sleep.
+ *
+ * @disable: Disable the clock atomically. Called with clk->enable_lock held.
+ * This function must not sleep.
+ *
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts. If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+ int (*prepare)(struct clk *);
+ void (*unprepare)(struct clk *);
+ int (*enable)(struct clk *);
+ void (*disable)(struct clk *);
+ int (*get)(struct clk *);
+ void (*put)(struct clk *);
+ unsigned long (*get_rate)(struct clk *);
+ long (*round_rate)(struct clk *, unsigned long);
+ int (*set_rate)(struct clk *, unsigned long);
+ int (*set_parent)(struct clk *, struct clk *);
+ struct clk * (*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+ clk->enable_count = clk->prepare_count = 0;
+ spin_lock_init(&clk->enable_lock);
+ mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
*/
struct clk;
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+int clk_prepare(struct clk *clk) { return 0; }
+void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
/**
* clk_get - lookup and obtain a reference to a clock producer.
* @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_disable(struct clk *clk);
/**
* clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
* This is only valid once the clock source has been enabled.
+ * Returns zero if the clock rate is unknown.
* @clk: clock source
*/
unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
*/
void clk_put(struct clk *clk);
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
/**
* clk_round_rate - adjust a rate to the exact rate a clock can provide
* @clk: clock source
Hi all,
These patches are an attempt to allow platforms to share clock code. At
present, the definitions of 'struct clk' are local to platform code,
which makes allocating and initialising cross-platform clock sources
difficult, and makes it impossible to compile a single image containing
support for two ARM platforms with different struct clks.
The three patches are for the architecture-independent kernel code,
introducing the common clk infrastructure. The changelog for the first
patch includes details about the new clock definitions.
Many thanks to the following for their input:
* Benjamin Herrenschmidt <[email protected]>
* Ben Dooks <[email protected]>
* Baruch Siach <[email protected]>
* Russell King <[email protected]>
* Uwe Kleine-König <[email protected]>
* Lorenzo Pieralisi <[email protected]>
* Vincent Guittot <[email protected]>
* Sascha Hauer <[email protected]>
* Ryan Mallon <[email protected]>
* Colin Cross <[email protected]>
* Jassi Brar <[email protected]>
* Saravana Kannan <[email protected]>
Cheers,
Jeremy
--
v13:
* Don't expose __clk_get and clk_put - prototypes in clkdev.c instead
* Add might_sleep to clk_set_rate
* Comment clarifications & fixups
* Remove zero initialisers
* Fold warnings into main clk.c change
v12:
* Always refcount, even when enable/prepare ops are NULL
* Unify prepare & enable count checking
* Update comments for prepare/unprepare
* Use spin_{lock,unlock}_irqsave
* Change clk_put to __clk_put, and use the shared clk_put
v11:
* add prepare/unprepare for non-atomic switching, document atomicity
* move to drivers/clk/
v10:
* comment fixups, from Uwe's review
* added DEFINE_CLK_FIXED
v9:
* comment improvements
* kerneldoc fixups
* add WARN_ON to clk_disable
v8:
* add atomic clocks, and locking wrappers
* expand comments on clk and clk_ops
v7:
* change CLK_INIT to initialise clk->mutex statically
v6:
* fixed up references to 'clk_operations' in the changelog
v5:
* uninline main API, and share definitions with !USE_COMMON_STRUCT_CLK
* add __clk_get
* delay mutex init
* kerneldoc for struct clk
v4:
* use mutex for enable/disable locking
* DEFINE_CLK -> INIT_CLK, and pass the clk name for mutex init
* struct clk_operations -> struct clk_ops
v3:
* do clock usage refcounting in common code
* provide sample port
v2:
* no longer ARM-specific
* use clk_operations
---
Jeremy Kerr (2):
Add a common struct clk
clk: Generic support for fixed-rate clocks
Since most platforms will need a fixed-rate clock, add one. This will
also serve as a basic example of an implementation of struct clk.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/clk.c | 14 ++++++++++++++
include/linux/clk.h | 16 ++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 0bc9c6f..0da0bb9 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -130,3 +130,17 @@ void __clk_put(struct clk *clk)
if (clk->ops->put)
clk->ops->put(clk);
}
+
+/* clk_fixed support */
+
+#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
+
+static unsigned long clk_fixed_get_rate(struct clk *clk)
+{
+ return to_clk_fixed(clk)->rate;
+}
+
+struct clk_ops clk_fixed_ops = {
+ .get_rate = clk_fixed_get_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_ops);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 604be74..7c0808c 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -155,6 +155,22 @@ static inline void clk_common_init(struct clk *clk)
mutex_init(&clk->prepare_lock);
}
+/* Simple fixed-rate clock */
+struct clk_fixed {
+ struct clk clk;
+ unsigned long rate;
+};
+
+extern struct clk_ops clk_fixed_ops;
+
+#define INIT_CLK_FIXED(name, r) { \
+ .clk = INIT_CLK(name.clk, clk_fixed_ops), \
+ .rate = (r) \
+}
+
+#define DEFINE_CLK_FIXED(name, r) \
+ struct clk_fixed name = INIT_CLK_FIXED(name, r)
+
#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
On 02/21/2011 03:50 PM, Jeremy Kerr wrote:
> Since most platforms will need a fixed-rate clock, add one. This will
> also serve as a basic example of an implementation of struct clk.
>
> Signed-off-by: Jeremy Kerr <[email protected]>
>
> ---
> drivers/clk/clk.c | 14 ++++++++++++++
> include/linux/clk.h | 16 ++++++++++++++++
> 2 files changed, 30 insertions(+)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 0bc9c6f..0da0bb9 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -130,3 +130,17 @@ void __clk_put(struct clk *clk)
> if (clk->ops->put)
> clk->ops->put(clk);
> }
> +
> +/* clk_fixed support */
> +
> +#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
> +
> +static unsigned long clk_fixed_get_rate(struct clk *clk)
> +{
> + return to_clk_fixed(clk)->rate;
> +}
> +
> +struct clk_ops clk_fixed_ops = {
> + .get_rate = clk_fixed_get_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_fixed_ops);
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 604be74..7c0808c 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -155,6 +155,22 @@ static inline void clk_common_init(struct clk *clk)
> mutex_init(&clk->prepare_lock);
> }
>
> +/* Simple fixed-rate clock */
> +struct clk_fixed {
> + struct clk clk;
> + unsigned long rate;
If we never need to dynamically create fixed clocks (which seems
unlikely) then rate can be const.
~Ryan
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
[email protected] PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
Hi Ryan,
> If we never need to dynamically create fixed clocks (which seems
> unlikely) then rate can be const.
There's been a few cases where I've needed to set the rate of a fixed clock
during boot - for example when a clock rate varies between boards, it may be
defined in a platform-wide file, but have the rate modified early (ie,
clk_foo.rate = 32678) in a board file.
Also, if we're parsing clocks from the device tree (or any other discovery
mechanism), we'll need to modify rate.
Cheers,
Jeremy
Hi Jeremy,
On Mon, Feb 21, 2011 at 10:50:58AM +0800, Jeremy Kerr wrote:
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..604be74 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -11,18 +12,168 @@
> ...
> +#ifdef CONFIG_USE_COMMON_STRUCT_CLK
> ...
> +#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
>
> /*
> - * struct clk - an machine class defined object / cookie.
> + * Global clock object, actual structure is declared per-machine
> */
> struct clk;
>
> +static inline void clk_common_init(struct clk *clk) { }
> +
> +/*
> + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> + * functions are no-ops
> + */
> +int clk_prepare(struct clk *clk) { return 0; }
> +void clk_unprepare(struct clk *clk) { }
these should be static inline. Otherwise these functions end up in many
files and so provoke a build failure.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Signed-off-by: Uwe Kleine-König <[email protected]>
---
Hello,
on top of .38-rc6 + making the clk_{un,}prepare stubs static inline,
this patch makes use of Jeremy's common struct clk (v13) on a i.MX27 based
machine.
This is compile tested using mx21_defconfig and runtime tested using
mx27_defconfig.
I had to degrade one WARN_ON to WARN_ON_ONCE in drivers/clk/clk.c to
actually make it work. Otherwise console output results in a warning
that results in console output ...
Best regards
Uwe
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-imx/clock-imx27.c | 186 ++++++++++++++++--------------
arch/arm/plat-mxc/clock.c | 127 +++++++++++++++++++++
arch/arm/plat-mxc/include/mach/clkdev.h | 4 +
arch/arm/plat-mxc/include/mach/clock.h | 32 ++++--
drivers/clk/clk.c | 2 +-
6 files changed, 255 insertions(+), 97 deletions(-)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 56684b5..f2d3708 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -30,6 +30,7 @@ config SOC_IMX27
select IMX_HAVE_DMA_V1
select IMX_HAVE_IOMUX_V1
select MXC_AVIC
+ select USE_COMMON_STRUCT_CLK
if ARCH_MX1
diff --git a/arch/arm/mach-imx/clock-imx27.c b/arch/arm/mach-imx/clock-imx27.c
index 583f251..f413f7b 100644
--- a/arch/arm/mach-imx/clock-imx27.c
+++ b/arch/arm/mach-imx/clock-imx27.c
@@ -68,35 +68,35 @@
#define CCM_SPCTL1_LF (1 << 15)
#define CCM_SPCTL1_BRMO (1 << 6)
-static struct clk mpll_main1_clk, mpll_main2_clk;
+static struct clk_mxc mpll_main1_clk, mpll_main2_clk;
-static int clk_pccr_enable(struct clk *clk)
+static int clk_pccr_enable(struct clk_mxc *clk_mxc)
{
unsigned long reg;
- if (!clk->enable_reg)
+ if (!clk_mxc->enable_reg)
return 0;
- reg = __raw_readl(clk->enable_reg);
- reg |= 1 << clk->enable_shift;
- __raw_writel(reg, clk->enable_reg);
+ reg = __raw_readl(clk_mxc->enable_reg);
+ reg |= 1 << clk_mxc->enable_shift;
+ __raw_writel(reg, clk_mxc->enable_reg);
return 0;
}
-static void clk_pccr_disable(struct clk *clk)
+static void clk_pccr_disable(struct clk_mxc *clk_mxc)
{
unsigned long reg;
- if (!clk->enable_reg)
+ if (!clk_mxc->enable_reg)
return;
- reg = __raw_readl(clk->enable_reg);
- reg &= ~(1 << clk->enable_shift);
- __raw_writel(reg, clk->enable_reg);
+ reg = __raw_readl(clk_mxc->enable_reg);
+ reg &= ~(1 << clk_mxc->enable_shift);
+ __raw_writel(reg, clk_mxc->enable_reg);
}
-static int clk_spll_enable(struct clk *clk)
+static int clk_spll_enable(struct clk_mxc *clk_mxc)
{
unsigned long reg;
@@ -109,7 +109,7 @@ static int clk_spll_enable(struct clk *clk)
return 0;
}
-static void clk_spll_disable(struct clk *clk)
+static void clk_spll_disable(struct clk_mxc *clk_mxc)
{
unsigned long reg;
@@ -118,11 +118,11 @@ static void clk_spll_disable(struct clk *clk)
__raw_writel(reg, CCM_CSCR);
}
-static int clk_cpu_set_parent(struct clk *clk, struct clk *parent)
+static int clk_cpu_set_parent(struct clk_mxc *clk_mxc, struct clk_mxc *parent)
{
int cscr = __raw_readl(CCM_CSCR);
- if (clk->parent == parent)
+ if (clk_mxc->parent == parent)
return 0;
if (mx27_revision() >= IMX_CHIP_REVISION_2_0) {
@@ -135,18 +135,18 @@ static int clk_cpu_set_parent(struct clk *clk, struct clk *parent)
return -EINVAL;
}
__raw_writel(cscr, CCM_CSCR);
- clk->parent = parent;
+ clk_mxc->parent = parent;
return 0;
}
return -ENODEV;
}
-static unsigned long round_rate_cpu(struct clk *clk, unsigned long rate)
+static unsigned long round_rate_cpu(struct clk_mxc *clk_mxc, unsigned long rate)
{
int div;
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
div = parent_rate / rate;
if (parent_rate % rate)
@@ -158,13 +158,13 @@ static unsigned long round_rate_cpu(struct clk *clk, unsigned long rate)
return parent_rate / div;
}
-static int set_rate_cpu(struct clk *clk, unsigned long rate)
+static int set_rate_cpu(struct clk_mxc *clk_mxc, unsigned long rate)
{
unsigned int div;
uint32_t reg;
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
div = parent_rate / rate;
@@ -186,12 +186,12 @@ static int set_rate_cpu(struct clk *clk, unsigned long rate)
return 0;
}
-static unsigned long round_rate_per(struct clk *clk, unsigned long rate)
+static unsigned long round_rate_per(struct clk_mxc *clk_mxc, unsigned long rate)
{
u32 div;
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
div = parent_rate / rate;
if (parent_rate % rate)
@@ -203,15 +203,15 @@ static unsigned long round_rate_per(struct clk *clk, unsigned long rate)
return parent_rate / div;
}
-static int set_rate_per(struct clk *clk, unsigned long rate)
+static int set_rate_per(struct clk_mxc *clk_mxc, unsigned long rate)
{
u32 reg;
u32 div;
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
- if (clk->id < 0 || clk->id > 3)
+ if (clk_mxc->id < 0 || clk_mxc->id > 3)
return -EINVAL;
div = parent_rate / rate;
@@ -219,30 +219,30 @@ static int set_rate_per(struct clk *clk, unsigned long rate)
return -EINVAL;
div--;
- reg = __raw_readl(CCM_PCDR1) & ~(0x3f << (clk->id << 3));
- reg |= div << (clk->id << 3);
+ reg = __raw_readl(CCM_PCDR1) & ~(0x3f << (clk_mxc->id << 3));
+ reg |= div << (clk_mxc->id << 3);
__raw_writel(reg, CCM_PCDR1);
return 0;
}
-static unsigned long get_rate_usb(struct clk *clk)
+static unsigned long get_rate_usb(struct clk_mxc *clk_mxc)
{
unsigned long usb_pdf;
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
usb_pdf = (__raw_readl(CCM_CSCR) >> 28) & 0x7;
return parent_rate / (usb_pdf + 1U);
}
-static unsigned long get_rate_ssix(struct clk *clk, unsigned long pdf)
+static unsigned long get_rate_ssix(struct clk_mxc *clk_mxc, unsigned long pdf)
{
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
if (mx27_revision() >= IMX_CHIP_REVISION_2_0)
pdf += 4; /* MX27 TO2+ */
@@ -252,22 +252,22 @@ static unsigned long get_rate_ssix(struct clk *clk, unsigned long pdf)
return 2UL * parent_rate / pdf;
}
-static unsigned long get_rate_ssi1(struct clk *clk)
+static unsigned long get_rate_ssi1(struct clk_mxc *clk_mxc)
{
- return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 16) & 0x3f);
+ return get_rate_ssix(clk_mxc, (__raw_readl(CCM_PCDR0) >> 16) & 0x3f);
}
-static unsigned long get_rate_ssi2(struct clk *clk)
+static unsigned long get_rate_ssi2(struct clk_mxc *clk_mxc)
{
- return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 26) & 0x3f);
+ return get_rate_ssix(clk_mxc, (__raw_readl(CCM_PCDR0) >> 26) & 0x3f);
}
-static unsigned long get_rate_nfc(struct clk *clk)
+static unsigned long get_rate_nfc(struct clk_mxc *clk_mxc)
{
unsigned long nfc_pdf;
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
if (mx27_revision() >= IMX_CHIP_REVISION_2_0)
nfc_pdf = (__raw_readl(CCM_PCDR0) >> 6) & 0xf;
@@ -277,12 +277,12 @@ static unsigned long get_rate_nfc(struct clk *clk)
return parent_rate / (nfc_pdf + 1);
}
-static unsigned long get_rate_vpu(struct clk *clk)
+static unsigned long get_rate_vpu(struct clk_mxc *clk_mxc)
{
unsigned long vpu_pdf;
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
if (mx27_revision() >= IMX_CHIP_REVISION_2_0) {
vpu_pdf = (__raw_readl(CCM_PCDR0) >> 10) & 0x3f;
@@ -295,25 +295,25 @@ static unsigned long get_rate_vpu(struct clk *clk)
return 2UL * parent_rate / vpu_pdf;
}
-static unsigned long round_rate_parent(struct clk *clk, unsigned long rate)
+static unsigned long round_rate_parent(struct clk_mxc *clk_mxc, unsigned long rate)
{
- return clk->parent->round_rate(clk->parent, rate);
+ return clk_round_rate(&clk_mxc->parent->clk, rate);
}
-static unsigned long get_rate_parent(struct clk *clk)
+static unsigned long get_rate_parent(struct clk_mxc *clk_mxc)
{
- return clk_get_rate(clk->parent);
+ return clk_get_rate(&clk_mxc->parent->clk);
}
-static int set_rate_parent(struct clk *clk, unsigned long rate)
+static int set_rate_parent(struct clk_mxc *clk_mxc, unsigned long rate)
{
- return clk->parent->set_rate(clk->parent, rate);
+ return clk_set_rate(&clk_mxc->parent->clk, rate);
}
/* in Hz */
static unsigned long external_high_reference = 26000000;
-static unsigned long get_rate_high_reference(struct clk *clk)
+static unsigned long get_rate_high_reference(struct clk_mxc *clk)
{
return external_high_reference;
}
@@ -321,44 +321,44 @@ static unsigned long get_rate_high_reference(struct clk *clk)
/* in Hz */
static unsigned long external_low_reference = 32768;
-static unsigned long get_rate_low_reference(struct clk *clk)
+static unsigned long get_rate_low_reference(struct clk_mxc *clk_mxc)
{
return external_low_reference;
}
-static unsigned long get_rate_fpm(struct clk *clk)
+static unsigned long get_rate_fpm(struct clk_mxc *clk_mxc)
{
- return clk_get_rate(clk->parent) * 1024;
+ return clk_get_rate(&clk_mxc->parent->clk) * 1024;
}
-static unsigned long get_rate_mpll(struct clk *clk)
+static unsigned long get_rate_mpll(struct clk_mxc *clk_mxc)
{
return mxc_decode_pll(__raw_readl(CCM_MPCTL0),
- clk_get_rate(clk->parent));
+ clk_get_rate(&clk_mxc->parent->clk));
}
-static unsigned long get_rate_mpll_main(struct clk *clk)
+static unsigned long get_rate_mpll_main(struct clk_mxc *clk_mxc)
{
unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
/* i.MX27 TO2:
* clk->id == 0: arm clock source path 1 which is from 2 * MPLL / 2
* clk->id == 1: arm clock source path 2 which is from 2 * MPLL / 3
*/
- if (mx27_revision() >= IMX_CHIP_REVISION_2_0 && clk->id == 1)
+ if (mx27_revision() >= IMX_CHIP_REVISION_2_0 && clk_mxc->id == 1)
return 2UL * parent_rate / 3UL;
return parent_rate;
}
-static unsigned long get_rate_spll(struct clk *clk)
+static unsigned long get_rate_spll(struct clk_mxc *clk_mxc)
{
uint32_t reg;
unsigned long rate;
- rate = clk_get_rate(clk->parent);
+ rate = clk_get_rate(&clk_mxc->parent->clk);
reg = __raw_readl(CCM_SPCTL0);
@@ -371,7 +371,7 @@ static unsigned long get_rate_spll(struct clk *clk)
return mxc_decode_pll(reg, rate);
}
-static unsigned long get_rate_cpu(struct clk *clk)
+static unsigned long get_rate_cpu(struct clk_mxc *clk_mxc)
{
u32 div;
unsigned long rate;
@@ -381,11 +381,11 @@ static unsigned long get_rate_cpu(struct clk *clk)
else
div = (__raw_readl(CCM_CSCR) >> 13) & 0x7;
- rate = clk_get_rate(clk->parent);
+ rate = clk_get_rate(&clk_mxc->parent->clk);
return rate / (div + 1);
}
-static unsigned long get_rate_ahb(struct clk *clk)
+static unsigned long get_rate_ahb(struct clk_mxc *clk_mxc)
{
unsigned long rate, bclk_pdf;
@@ -394,33 +394,33 @@ static unsigned long get_rate_ahb(struct clk *clk)
else
bclk_pdf = (__raw_readl(CCM_CSCR) >> 9) & 0xf;
- rate = clk_get_rate(clk->parent);
+ rate = clk_get_rate(&clk_mxc->parent->clk);
return rate / (bclk_pdf + 1);
}
-static unsigned long get_rate_ipg(struct clk *clk)
+static unsigned long get_rate_ipg(struct clk_mxc *clk_mxc)
{
unsigned long rate, ipg_pdf;
if (mx27_revision() >= IMX_CHIP_REVISION_2_0)
- return clk_get_rate(clk->parent);
+ return clk_get_rate(&clk_mxc->parent->clk);
else
ipg_pdf = (__raw_readl(CCM_CSCR) >> 8) & 1;
- rate = clk_get_rate(clk->parent);
+ rate = clk_get_rate(&clk_mxc->parent->clk);
return rate / (ipg_pdf + 1);
}
-static unsigned long get_rate_per(struct clk *clk)
+static unsigned long get_rate_per(struct clk_mxc *clk_mxc)
{
unsigned long perclk_pdf, parent_rate;
- parent_rate = clk_get_rate(clk->parent);
+ parent_rate = clk_get_rate(&clk_mxc->parent->clk);
- if (clk->id < 0 || clk->id > 3)
+ if (clk_mxc->id < 0 || clk_mxc->id > 3)
return 0;
- perclk_pdf = (__raw_readl(CCM_PCDR1) >> (clk->id << 3)) & 0x3f;
+ perclk_pdf = (__raw_readl(CCM_PCDR1) >> (clk_mxc->id << 3)) & 0x3f;
return parent_rate / (perclk_pdf + 1);
}
@@ -430,11 +430,13 @@ static unsigned long get_rate_per(struct clk *clk)
* Default case is 26MHz. Could be changed at runtime
* with a call to change_external_high_reference()
*/
-static struct clk ckih_clk = {
+static struct clk_mxc ckih_clk = {
+ .clk = INIT_CLK_MXC(ckih_clk),
.get_rate = get_rate_high_reference,
};
-static struct clk mpll_clk = {
+static struct clk_mxc mpll_clk = {
+ .clk = INIT_CLK_MXC(mpll_clk),
.parent = &ckih_clk,
.get_rate = get_rate_mpll,
};
@@ -442,7 +444,8 @@ static struct clk mpll_clk = {
/* For i.MX27 TO2, it is the MPLL path 1 of ARM core
* It provides the clock source whose rate is same as MPLL
*/
-static struct clk mpll_main1_clk = {
+static struct clk_mxc mpll_main1_clk = {
+ .clk = INIT_CLK_MXC(mpll_main1_clk),
.id = 0,
.parent = &mpll_clk,
.get_rate = get_rate_mpll_main,
@@ -451,23 +454,27 @@ static struct clk mpll_main1_clk = {
/* For i.MX27 TO2, it is the MPLL path 2 of ARM core
* It provides the clock source whose rate is same MPLL * 2 / 3
*/
-static struct clk mpll_main2_clk = {
+static struct clk_mxc mpll_main2_clk = {
+ .clk = INIT_CLK_MXC(mpll_main2_clk),
.id = 1,
.parent = &mpll_clk,
.get_rate = get_rate_mpll_main,
};
-static struct clk ahb_clk = {
+static struct clk_mxc ahb_clk = {
+ .clk = INIT_CLK_MXC(ahb_clk),
.parent = &mpll_main2_clk,
.get_rate = get_rate_ahb,
};
-static struct clk ipg_clk = {
+static struct clk_mxc ipg_clk = {
+ .clk = INIT_CLK_MXC(ipg_clk),
.parent = &ahb_clk,
.get_rate = get_rate_ipg,
};
-static struct clk cpu_clk = {
+static struct clk_mxc cpu_clk = {
+ .clk = INIT_CLK_MXC(cpu_clk),
.parent = &mpll_main2_clk,
.set_parent = clk_cpu_set_parent,
.round_rate = round_rate_cpu,
@@ -475,7 +482,8 @@ static struct clk cpu_clk = {
.set_rate = set_rate_cpu,
};
-static struct clk spll_clk = {
+static struct clk_mxc spll_clk = {
+ .clk = INIT_CLK_MXC(spll_clk),
.parent = &ckih_clk,
.get_rate = get_rate_spll,
.enable = clk_spll_enable,
@@ -486,12 +494,14 @@ static struct clk spll_clk = {
* the low frequency external clock reference
* Default case is 32.768kHz.
*/
-static struct clk ckil_clk = {
+static struct clk_mxc ckil_clk = {
+ .clk = INIT_CLK_MXC(ckil_clk),
.get_rate = get_rate_low_reference,
};
/* Output of frequency pre multiplier */
-static struct clk fpm_clk = {
+static struct clk_mxc fpm_clk = {
+ .clk = INIT_CLK_MXC(fpm_clk),
.parent = &ckil_clk,
.get_rate = get_rate_fpm,
};
@@ -500,7 +510,8 @@ static struct clk fpm_clk = {
#define PCCR1 CCM_PCCR1
#define DEFINE_CLOCK(name, i, er, es, gr, s, p) \
- static struct clk name = { \
+ static struct clk_mxc name = { \
+ .clk = INIT_CLK_MXC(name), \
.id = i, \
.enable_reg = er, \
.enable_shift = es, \
@@ -512,7 +523,8 @@ static struct clk fpm_clk = {
}
#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p) \
- static struct clk name = { \
+ static struct clk_mxc name = { \
+ .clk = INIT_CLK_MXC(name), \
.id = i, \
.enable_reg = er, \
.enable_shift = es, \
@@ -526,7 +538,7 @@ static struct clk fpm_clk = {
}
/* Forward declaration to keep the following list in order */
-static struct clk slcdc_clk1, sahara2_clk1, rtic_clk1, fec_clk1, emma_clk1,
+static struct clk_mxc slcdc_clk1, sahara2_clk1, rtic_clk1, fec_clk1, emma_clk1,
dma_clk1, lcdc_clk2, vpu_clk1;
/* All clocks we can gate through PCCRx in the order of PCCRx bits */
@@ -620,7 +632,7 @@ DEFINE_CLOCK1(csi_clk, 0, NULL, 0, parent, &csi_clk1, &per4_clk);
{ \
.dev_id = d, \
.con_id = n, \
- .clk = &c, \
+ .clk = &c.clk, \
},
static struct clk_lookup lookups[] = {
@@ -746,16 +758,16 @@ int __init mx27_clocks_init(unsigned long fref)
spll_clk.disable(&spll_clk);
/* enable basic clocks */
- clk_enable(&per1_clk);
- clk_enable(&gpio_clk);
- clk_enable(&emi_clk);
- clk_enable(&iim_clk);
+ clk_enable(&per1_clk.clk);
+ clk_enable(&gpio_clk.clk);
+ clk_enable(&emi_clk.clk);
+ clk_enable(&iim_clk.clk);
#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC)
- clk_enable(&uart1_clk);
+ clk_enable(&uart1_clk.clk);
#endif
- mxc_timer_init(&gpt1_clk, MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR),
+ mxc_timer_init(&gpt1_clk.clk, MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR),
MX27_INT_GPT1);
return 0;
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 2ed3ab1..3fc75dd 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -44,6 +44,131 @@
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+static int clk_mxc_enable(struct clk *clk)
+{
+ struct clk_mxc *clk_mxc = to_clk_mxc(clk);
+ int ret = 0;
+
+ if (clk_mxc->parent)
+ ret = clk_enable(&clk_mxc->parent->clk);
+
+ if (!ret && clk_mxc->secondary)
+ ret = clk_enable(&clk_mxc->secondary->clk);
+
+ if (!ret && clk_mxc->enable)
+ ret = clk_mxc->enable(clk_mxc);
+
+ return ret;
+}
+
+static void clk_mxc_disable(struct clk *clk)
+{
+ struct clk_mxc *clk_mxc = to_clk_mxc(clk);
+
+ if (clk_mxc->disable)
+ clk_mxc->disable(clk_mxc);
+
+ if (clk_mxc->secondary)
+ clk_disable(&clk_mxc->secondary->clk);
+
+ if (clk_mxc->parent)
+ clk_disable(&clk_mxc->parent->clk);
+}
+
+static unsigned long clk_mxc_get_rate(struct clk *clk)
+{
+ struct clk_mxc *clk_mxc = to_clk_mxc(clk);
+
+ if (clk_mxc->get_rate)
+ return clk_mxc->get_rate(clk_mxc);
+ else if (clk_mxc->parent)
+ return clk_get_rate(&clk_mxc->parent->clk);
+ else
+ return 0UL;
+}
+
+static long clk_mxc_round_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk_mxc *clk_mxc = to_clk_mxc(clk);
+
+ if (clk_mxc->round_rate)
+ return clk_mxc->round_rate(clk_mxc, rate);
+
+ return 0L;
+}
+
+static int clk_mxc_set_rate(struct clk *clk, unsigned long rate)
+{
+ struct clk_mxc *clk_mxc = to_clk_mxc(clk);
+ int ret = -EINVAL;
+
+ if (clk_mxc->set_rate && rate != 0)
+ ret = clk_mxc->set_rate(clk_mxc, rate);
+
+ return ret;
+}
+
+static int clk_mxc_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_mxc *clk_mxc = to_clk_mxc(clk);
+ struct clk *old_parent = parent;
+ struct clk_mxc *parent_mxc = to_clk_mxc(parent);
+ int ret;
+
+ if (!clk_mxc->set_parent)
+ return -EINVAL;
+
+ if (clk->prepare_count) {
+ ret = clk_prepare(parent);
+ if (ret)
+ goto err_prepare_parent;
+ }
+
+ if (clk->enable_count) {
+ ret = clk_enable(parent);
+ if (ret)
+ goto err_enable_parent;
+ }
+
+ ret = clk_mxc->set_parent(clk_mxc, parent_mxc);
+ if (ret == 0) {
+ old_parent = &clk_mxc->parent->clk;
+ clk_mxc->parent = to_clk_mxc(parent);
+ }
+
+ if (clk->enable_count)
+ clk_disable(old_parent);
+err_enable_parent:
+
+ if (clk->prepare_count)
+ clk_unprepare(old_parent);
+err_prepare_parent:
+
+ return ret;
+}
+
+static struct clk *clk_mxc_get_parent(struct clk *clk)
+{
+ struct clk_mxc *clk_mxc = to_clk_mxc(clk);
+
+ if (clk_mxc->parent)
+ return &clk_mxc->parent->clk;
+
+ return NULL;
+}
+
+const struct clk_ops clk_mxc_ops = {
+ .enable = clk_mxc_enable,
+ .disable = clk_mxc_disable,
+ .get_rate = clk_mxc_get_rate,
+ .round_rate = clk_mxc_round_rate,
+ .set_rate = clk_mxc_set_rate,
+ .set_parent = clk_mxc_set_parent,
+ .get_parent = clk_mxc_get_parent,
+};
+#else
+
/*-------------------------------------------------------------------------
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
@@ -200,6 +325,8 @@ struct clk *clk_get_parent(struct clk *clk)
}
EXPORT_SYMBOL(clk_get_parent);
+#endif
+
/*
* Get the resulting clock rate from a PLL register value and the input
* frequency. PLLs with this register layout can at least be found on
diff --git a/arch/arm/plat-mxc/include/mach/clkdev.h b/arch/arm/plat-mxc/include/mach/clkdev.h
index 04b37a8..f663af3 100644
--- a/arch/arm/plat-mxc/include/mach/clkdev.h
+++ b/arch/arm/plat-mxc/include/mach/clkdev.h
@@ -1,7 +1,11 @@
#ifndef __ASM_MACH_CLKDEV_H
#define __ASM_MACH_CLKDEV_H
+#ifndef CONFIG_USE_COMMON_STRUCT_CLK
+
#define __clk_get(clk) ({ 1; })
#define __clk_put(clk) do { } while (0)
#endif
+
+#endif
diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h
index 753a598..d8efa77 100644
--- a/arch/arm/plat-mxc/include/mach/clock.h
+++ b/arch/arm/plat-mxc/include/mach/clock.h
@@ -23,14 +23,24 @@
#ifndef __ASSEMBLY__
#include <linux/list.h>
+#include <linux/clk.h>
+
struct module;
-struct clk {
+#ifndef CONFIG_USE_COMMON_STRUCT_CLK
+#define clk_mxc clk
+#endif
+
+struct clk_mxc {
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+ struct clk clk;
+#endif
+
int id;
/* Source clock this clk depends on */
- struct clk *parent;
+ struct clk_mxc *parent;
/* Secondary clock to enable/disable with this clock */
- struct clk *secondary;
+ struct clk_mxc *secondary;
/* Reference count of clock enable/disable */
__s8 usecount;
/* Register bit position for clock's enable/disable control. */
@@ -39,23 +49,27 @@ struct clk {
void __iomem *enable_reg;
u32 flags;
/* get the current clock rate (always a fresh value) */
- unsigned long (*get_rate) (struct clk *);
+ unsigned long (*get_rate) (struct clk_mxc *);
/* Function ptr to set the clock to a new rate. The rate must match a
supported rate returned from round_rate. Leave blank if clock is not
programmable */
- int (*set_rate) (struct clk *, unsigned long);
+ int (*set_rate) (struct clk_mxc *, unsigned long);
/* Function ptr to round the requested clock rate to the nearest
supported rate that is less than or equal to the requested rate. */
- unsigned long (*round_rate) (struct clk *, unsigned long);
+ unsigned long (*round_rate) (struct clk_mxc *, unsigned long);
/* Function ptr to enable the clock. Leave blank if clock can not
be gated. */
- int (*enable) (struct clk *);
+ int (*enable) (struct clk_mxc *);
/* Function ptr to disable the clock. Leave blank if clock can not
be gated. */
- void (*disable) (struct clk *);
+ void (*disable) (struct clk_mxc *);
/* Function ptr to set the parent clock of the clock. */
- int (*set_parent) (struct clk *, struct clk *);
+ int (*set_parent) (struct clk_mxc *, struct clk_mxc *);
};
+#define to_clk_mxc(_clk_mxc) container_of(_clk_mxc, struct clk_mxc, clk)
+
+extern const struct clk_ops clk_mxc_ops;
+#define INIT_CLK_MXC(name) INIT_CLK(name.clk, clk_mxc_ops)
int clk_register(struct clk *clk);
void clk_unregister(struct clk *clk);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 0da0bb9..fbafcb6 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -47,7 +47,7 @@ int clk_enable(struct clk *clk)
unsigned long flags;
int ret = 0;
- WARN_ON(clk->prepare_count == 0);
+ WARN_ON_ONCE(clk->prepare_count == 0);
spin_lock_irqsave(&clk->enable_lock, flags);
if (clk->enable_count == 0 && clk->ops->enable)
--
1.7.2.3
Hi Uwe,
> > +static inline void clk_common_init(struct clk *clk) { }
> > +
> > +/*
> > + * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
> > + * requirements for clk_enable/clk_disable, so the prepare and unprepare
> > + * functions are no-ops
> > + */
> > +int clk_prepare(struct clk *clk) { return 0; }
> > +void clk_unprepare(struct clk *clk) { }
>
> these should be static inline. Otherwise these functions end up in many
> files and so provoke a build failure.
Ugh, brown paper bag time. Thanks for that, I'll update this patch.
Cheers,
Jeremy
On 02/22/2011 03:33 PM, Uwe Kleine-König wrote:
> Signed-off-by: Uwe Kleine-König<[email protected]>
> ---
> Hello,
>
> on top of .38-rc6 + making the clk_{un,}prepare stubs static inline,
> this patch makes use of Jeremy's common struct clk (v13) on a i.MX27 based
> machine.
>
> This is compile tested using mx21_defconfig and runtime tested using
> mx27_defconfig.
>
> I had to degrade one WARN_ON to WARN_ON_ONCE in drivers/clk/clk.c to
> actually make it work. Otherwise console output results in a warning
> that results in console output ...
You won't be able to do mainline the WARN_ON_ONCE because that will only
warn for the first clock that violates whatever condition it's warning
about.
Your probably need to fix your serial driver. What serial driver are you
using?
-Saravana
Hi Saravana,
On Tue, Feb 22, 2011 at 08:17:01PM -0800, Saravana Kannan wrote:
> On 02/22/2011 03:33 PM, Uwe Kleine-K?nig wrote:
> >I had to degrade one WARN_ON to WARN_ON_ONCE in drivers/clk/clk.c to
> >actually make it work. Otherwise console output results in a warning
> >that results in console output ...
>
> You won't be able to do mainline the WARN_ON_ONCE because that will
> only warn for the first clock that violates whatever condition it's
> warning about.
I wonder if it is more sensible while the warning is new. But I don't
care much because I'm going to fix the serial driver before switching.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Since most platforms will need a fixed-rate clock, add one. This will
also serve as a basic example of an implementation of struct clk.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/clk.c | 14 ++++++++++++++
include/linux/clk.h | 16 ++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 0bc9c6f..0da0bb9 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -130,3 +130,17 @@ void __clk_put(struct clk *clk)
if (clk->ops->put)
clk->ops->put(clk);
}
+
+/* clk_fixed support */
+
+#define to_clk_fixed(clk) (container_of(clk, struct clk_fixed, clk))
+
+static unsigned long clk_fixed_get_rate(struct clk *clk)
+{
+ return to_clk_fixed(clk)->rate;
+}
+
+struct clk_ops clk_fixed_ops = {
+ .get_rate = clk_fixed_get_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fixed_ops);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 7b406bd..d2f0db0 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -155,6 +155,22 @@ static inline void clk_common_init(struct clk *clk)
mutex_init(&clk->prepare_lock);
}
+/* Simple fixed-rate clock */
+struct clk_fixed {
+ struct clk clk;
+ unsigned long rate;
+};
+
+extern struct clk_ops clk_fixed_ops;
+
+#define INIT_CLK_FIXED(name, r) { \
+ .clk = INIT_CLK(name.clk, clk_fixed_ops), \
+ .rate = (r) \
+}
+
+#define DEFINE_CLK_FIXED(name, r) \
+ struct clk_fixed name = INIT_CLK_FIXED(name, r)
+
#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
Hi all,
These patches are an attempt to allow platforms to share clock code. At
present, the definitions of 'struct clk' are local to platform code,
which makes allocating and initialising cross-platform clock sources
difficult, and makes it impossible to compile a single image containing
support for two ARM platforms with different struct clks.
The three patches are for the architecture-independent kernel code,
introducing the common clk infrastructure. The changelog for the first
patch includes details about the new clock definitions.
Many thanks to the following for their input:
* Benjamin Herrenschmidt <[email protected]>
* Ben Dooks <[email protected]>
* Baruch Siach <[email protected]>
* Russell King <[email protected]>
* Uwe Kleine-König <[email protected]>
* Lorenzo Pieralisi <[email protected]>
* Vincent Guittot <[email protected]>
* Sascha Hauer <[email protected]>
* Ryan Mallon <[email protected]>
* Colin Cross <[email protected]>
* Jassi Brar <[email protected]>
* Saravana Kannan <[email protected]>
Cheers,
Jeremy
--
v14:
* make empty clk_prepare & clk_unprepare static inline
v13:
* Don't expose __clk_get and clk_put - prototypes in clkdev.c instead
* Add might_sleep to clk_set_rate
* Comment clarifications & fixups
* Remove zero initialisers
* Fold warnings into main clk.c change
v12:
* Always refcount, even when enable/prepare ops are NULL
* Unify prepare & enable count checking
* Update comments for prepare/unprepare
* Use spin_{lock,unlock}_irqsave
* Change clk_put to __clk_put, and use the shared clk_put
v11:
* add prepare/unprepare for non-atomic switching, document atomicity
* move to drivers/clk/
v10:
* comment fixups, from Uwe's review
* added DEFINE_CLK_FIXED
v9:
* comment improvements
* kerneldoc fixups
* add WARN_ON to clk_disable
v8:
* add atomic clocks, and locking wrappers
* expand comments on clk and clk_ops
v7:
* change CLK_INIT to initialise clk->mutex statically
v6:
* fixed up references to 'clk_operations' in the changelog
v5:
* uninline main API, and share definitions with !USE_COMMON_STRUCT_CLK
* add __clk_get
* delay mutex init
* kerneldoc for struct clk
v4:
* use mutex for enable/disable locking
* DEFINE_CLK -> INIT_CLK, and pass the clk name for mutex init
* struct clk_operations -> struct clk_ops
v3:
* do clock usage refcounting in common code
* provide sample port
v2:
* no longer ARM-specific
* use clk_operations
---
Jeremy Kerr (2):
Add a common struct clk
clk: Generic support for fixed-rate clocks
We currently have ~21 definitions of struct clk in the ARM architecture,
each defined on a per-platform basis. This makes it difficult to define
platform- (or architecture-) independent clock sources without making
assumptions about struct clk, and impossible to compile two
platforms with different struct clks into a single image.
This change is an effort to unify struct clk where possible, by defining
a common struct clk, containing a set of clock operations. Different
clock implementations can set their own operations, and have a standard
interface for generic code. The callback interface is exposed to the
kernel proper, while the clock implementations only need to be seen by
the platform internals.
This allows us to share clock code among platforms, and makes it
possible to dynamically create clock devices in platform-independent
code.
Platforms can enable the generic struct clock through
CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
consists of a common struct clk:
struct clk {
const struct clk_ops *ops;
unsigned int enable_count;
unsigned int prepare_count;
spinlock_t enable_lock;
struct mutex prepare_lock;
};
And a set of clock operations (defined per type of clock):
struct clk_ops {
int (*enable)(struct clk *);
void (*disable)(struct clk *);
unsigned long (*get_rate)(struct clk *);
[...]
};
To define a hardware-specific clock, machine code can "subclass" the
struct clock into a new struct (adding any device-specific data), and
provide a set of operations:
struct clk_foo {
struct clk clk;
void __iomem *some_register;
};
struct clk_ops clk_foo_ops = {
.get_rate = clk_foo_get_rate,
};
The common clock definitions are based on a development patch from Ben
Herrenschmidt <[email protected]>.
Signed-off-by: Jeremy Kerr <[email protected]>
---
drivers/clk/Kconfig | 3
drivers/clk/Makefile | 1
drivers/clk/clk.c | 132 ++++++++++++++++++++++++++++++++++
drivers/clk/clkdev.c | 7 +
include/linux/clk.h | 164 ++++++++++++++++++++++++++++++++++++++++---
5 files changed, 298 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 4168c88..6e3ae54 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -2,3 +2,6 @@
config CLKDEV_LOOKUP
bool
select HAVE_CLK
+
+config USE_COMMON_STRUCT_CLK
+ bool
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 07613fa..a1a06d3 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
+obj-$(CONFIG_USE_COMMON_STRUCT_CLK) += clk.o
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..0bc9c6f
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2011 Canonical Ltd <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Standard functionality for the common clock API.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+
+int clk_prepare(struct clk *clk)
+{
+ int ret = 0;
+
+ mutex_lock(&clk->prepare_lock);
+ if (clk->prepare_count == 0 && clk->ops->prepare)
+ ret = clk->ops->prepare(clk);
+
+ if (!ret)
+ clk->prepare_count++;
+ mutex_unlock(&clk->prepare_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_prepare);
+
+void clk_unprepare(struct clk *clk)
+{
+ mutex_lock(&clk->prepare_lock);
+
+ WARN_ON(clk->prepare_count == 0);
+
+ if (--clk->prepare_count == 0 && clk->ops->unprepare) {
+ WARN_ON(clk->enable_count != 0);
+ clk->ops->unprepare(clk);
+ }
+
+ mutex_unlock(&clk->prepare_lock);
+}
+EXPORT_SYMBOL_GPL(clk_unprepare);
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ WARN_ON(clk->prepare_count == 0);
+
+ spin_lock_irqsave(&clk->enable_lock, flags);
+ if (clk->enable_count == 0 && clk->ops->enable)
+ ret = clk->ops->enable(clk);
+
+ if (!ret)
+ clk->enable_count++;
+ spin_unlock_irqrestore(&clk->enable_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&clk->enable_lock, flags);
+
+ WARN_ON(clk->enable_count == 0);
+
+ if (!--clk->enable_count == 0 && clk->ops->disable)
+ clk->ops->disable(clk);
+
+ spin_unlock_irqrestore(&clk->enable_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk->ops->get_rate)
+ return clk->ops->get_rate(clk);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk->ops->round_rate)
+ return clk->ops->round_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ might_sleep();
+
+ if (clk->ops->set_rate)
+ return clk->ops->set_rate(clk, rate);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (clk->ops->set_parent)
+ return clk->ops->set_parent(clk, parent);
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (clk->ops->get_parent)
+ return clk->ops->get_parent(clk);
+ return ERR_PTR(-ENOSYS);
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+int __clk_get(struct clk *clk)
+{
+ if (clk->ops->get)
+ return clk->ops->get(clk);
+ return 1;
+}
+
+void __clk_put(struct clk *clk)
+{
+ if (clk->ops->put)
+ clk->ops->put(clk);
+}
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 0fc0a79..a7999d2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -23,6 +23,13 @@
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
+/* For USE_COMMON_STRUCT_CLK, these are provided in clk.c, but not exported
+ * through other headers; we don't want them used anywhere but here. */
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+extern int __clk_get(struct clk *clk);
+extern void __clk_put(struct clk *clk);
+#endif
+
/*
* Find the correct struct clk for the device and connection ID.
* We do slightly fuzzy matching here:
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 1d37f42..7b406bd 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
+ * Copyright (c) 2010-2011 Jeremy Kerr <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -11,18 +12,168 @@
#ifndef __LINUX_CLK_H
#define __LINUX_CLK_H
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+
struct device;
-/*
- * The base API.
+#ifdef CONFIG_USE_COMMON_STRUCT_CLK
+
+/* If we're using the common struct clk, we define the base clk object here */
+
+/**
+ * struct clk - hardware independent clock structure
+ * @ops: implementation-specific ops for this clock
+ * @enable_count: count of clk_enable() calls active on this clock
+ * @enable_lock: lock for atomic enable
+ * @prepare_count: count of clk_prepare() calls active on this clock
+ * @prepare_lock: lock for sleepable prepare
+ *
+ * The base clock object, used by drivers for hardware-independent manipulation
+ * of clock lines. This will be 'subclassed' by device-specific implementations,
+ * which add device-specific data to struct clk. For example:
+ *
+ * struct clk_foo {
+ * struct clk;
+ * [device specific fields]
+ * };
+ *
+ * The clock driver code will manage the device-specific data, and pass
+ * clk_foo.clk to the common clock code. The clock driver will be called
+ * through the @ops callbacks.
+ *
+ * The @enable_lock and @prepare_lock members are used to serialise accesses
+ * to the ops->enable and ops->prepare functions (and the corresponding
+ * ops->disable and ops->unprepare functions).
*/
+struct clk {
+ const struct clk_ops *ops;
+ unsigned int enable_count;
+ unsigned int prepare_count;
+ spinlock_t enable_lock;
+ struct mutex prepare_lock;
+};
+/* static initialiser for clocks. */
+#define INIT_CLK(name, o) { \
+ .ops = &o, \
+ .enable_lock = __SPIN_LOCK_UNLOCKED(name.enable_lock), \
+ .prepare_lock = __MUTEX_INITIALIZER(name.prepare_lock), \
+}
+
+/**
+ * struct clk_ops - Callback operations for clocks; these are to be provided
+ * by the clock implementation, and will be called by drivers through the clk_*
+ * API.
+ *
+ * @prepare: Prepare the clock for enabling. This must not return until
+ * the clock is fully prepared, and it's safe to call clk_enable.
+ * This callback is intended to allow clock implementations to
+ * do any initialisation that may sleep. Called with
+ * clk->prepare_lock held.
+ *
+ * @unprepare: Release the clock from its prepared state. This will typically
+ * undo any work done in the @prepare callback. Called with
+ * clk->prepare_lock held.
+ *
+ * @enable: Enable the clock atomically. This must not return until the
+ * clock is generating a valid clock signal, usable by consumer
+ * devices. Called with clk->enable_lock held. This function
+ * must not sleep.
+ *
+ * @disable: Disable the clock atomically. Called with clk->enable_lock held.
+ * This function must not sleep.
+ *
+ * @get: Called by the core clock code when a device driver acquires a
+ * clock via clk_get(). Optional.
+ *
+ * @put: Called by the core clock code when a devices driver releases a
+ * clock via clk_put(). Optional.
+ *
+ * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow
+ * implementations to split any work between atomic (enable) and sleepable
+ * (prepare) contexts. If a clock requires sleeping code to be turned on, this
+ * should be done in clk_prepare. Switching that will not sleep should be done
+ * in clk_enable.
+ *
+ * Typically, drivers will call clk_prepare when a clock may be needed later
+ * (eg. when a device is opened), and clk_enable when the clock is actually
+ * required (eg. from an interrupt). Note that clk_prepare *must* have been
+ * called before clk_enable.
+ *
+ * For other callbacks, see the corresponding clk_* functions. Parameters and
+ * return values are passed directly from/to these API functions, or
+ * -ENOSYS (or zero, in the case of clk_get_rate) is returned if the callback
+ * is NULL, see drivers/clk/clk.c for implementation details. All are optional.
+ */
+struct clk_ops {
+ int (*prepare)(struct clk *);
+ void (*unprepare)(struct clk *);
+ int (*enable)(struct clk *);
+ void (*disable)(struct clk *);
+ int (*get)(struct clk *);
+ void (*put)(struct clk *);
+ unsigned long (*get_rate)(struct clk *);
+ long (*round_rate)(struct clk *, unsigned long);
+ int (*set_rate)(struct clk *, unsigned long);
+ int (*set_parent)(struct clk *, struct clk *);
+ struct clk * (*get_parent)(struct clk *);
+};
+
+/**
+ * clk_prepare - prepare clock for atomic enabling.
+ *
+ * @clk: The clock to prepare
+ *
+ * Do any possibly sleeping initialisation on @clk, allowing the clock to be
+ * later enabled atomically (via clk_enable). This function may sleep.
+ */
+int clk_prepare(struct clk *clk);
+
+/**
+ * clk_unprepare - release clock from prepared state
+ *
+ * @clk: The clock to release
+ *
+ * Do any (possibly sleeping) cleanup on clk. This function may sleep.
+ */
+void clk_unprepare(struct clk *clk);
+
+/**
+ * clk_common_init - initialise a clock for driver usage
+ *
+ * @clk: The clock to initialise
+ *
+ * Used for runtime intialization of clocks; you don't need to call this
+ * if your clock has been (statically) initialized with INIT_CLK.
+ */
+static inline void clk_common_init(struct clk *clk)
+{
+ clk->enable_count = clk->prepare_count = 0;
+ spin_lock_init(&clk->enable_lock);
+ mutex_init(&clk->prepare_lock);
+}
+
+#else /* !CONFIG_USE_COMMON_STRUCT_CLK */
/*
- * struct clk - an machine class defined object / cookie.
+ * Global clock object, actual structure is declared per-machine
*/
struct clk;
+static inline void clk_common_init(struct clk *clk) { }
+
+/*
+ * For !CONFIG_USE_COMMON_STRUCT_CLK, we don't enforce any atomicity
+ * requirements for clk_enable/clk_disable, so the prepare and unprepare
+ * functions are no-ops
+ */
+static inline int clk_prepare(struct clk *clk) { return 0; }
+static inline void clk_unprepare(struct clk *clk) { }
+
+#endif /* !CONFIG_USE_COMMON_STRUCT_CLK */
+
/**
* clk_get - lookup and obtain a reference to a clock producer.
* @dev: device for clock "consumer"
@@ -67,6 +218,7 @@ void clk_disable(struct clk *clk);
/**
* clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
* This is only valid once the clock source has been enabled.
+ * Returns zero if the clock rate is unknown.
* @clk: clock source
*/
unsigned long clk_get_rate(struct clk *clk);
@@ -83,12 +235,6 @@ unsigned long clk_get_rate(struct clk *clk);
*/
void clk_put(struct clk *clk);
-
-/*
- * The remaining APIs are optional for machine class support.
- */
-
-
/**
* clk_round_rate - adjust a rate to the exact rate a clock can provide
* @clk: clock source
On Thu, Mar 03, 2011 at 02:40:29PM +0800, Jeremy Kerr wrote:
> Hi all,
>
> These patches are an attempt to allow platforms to share clock code. At
> present, the definitions of 'struct clk' are local to platform code,
> which makes allocating and initialising cross-platform clock sources
> difficult, and makes it impossible to compile a single image containing
> support for two ARM platforms with different struct clks.
>
> The three patches are for the architecture-independent kernel code,
> introducing the common clk infrastructure. The changelog for the first
> patch includes details about the new clock definitions.
>
> Many thanks to the following for their input:
> * Benjamin Herrenschmidt <[email protected]>
> * Ben Dooks <[email protected]>
> * Baruch Siach <[email protected]>
> * Russell King <[email protected]>
> * Uwe Kleine-K?nig <[email protected]>
> * Lorenzo Pieralisi <[email protected]>
> * Vincent Guittot <[email protected]>
> * Sascha Hauer <[email protected]>
> * Ryan Mallon <[email protected]>
> * Colin Cross <[email protected]>
> * Jassi Brar <[email protected]>
> * Saravana Kannan <[email protected]>
Tested-by: Uwe Kleine-K?nig <[email protected]>
who is responsible to take this patch? Russell?
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Hi Russell,
Any thughts on merging this? Would you like me to add to your patch tracking
system, or would you prefer it to go through some other path?
Cheers,
Jeremy
Hi all,
> Any thughts on merging this? Would you like me to add to your patch
> tracking system, or would you prefer it to go through some other path?
I haven't heard anything yet, so have added these two to the patch-tracking
system. Let me know if you'd prefer some other method of submission instead.
Cheers,
Jeremy
Hi Russell,
Any updates on these patches? I've added to your patch-tracker, would
you expect these to make the next merge window, or are there changes
you'd like made first?
Reason I ask is that I have a few queries from platform maintainers that
would like to complete their clock ports to this API, but don't want to
commit until the interface has been accepted, in at least an initial
form.
Cheers,
Jeremy
On Thu, Apr 14, 2011 at 12:20:59PM +0800, Jeremy Kerr wrote:
> Any updates on these patches? I've added to your patch-tracker, would
> you expect these to make the next merge window, or are there changes
> you'd like made first?
>
> Reason I ask is that I have a few queries from platform maintainers that
> would like to complete their clock ports to this API, but don't want to
> commit until the interface has been accepted, in at least an initial
> form.
I will take it, but at the moment I'm rather unhappy about the response
from the community to Linus' complaint.
If existing platform maintainers can show that moving over to this will
result in a net reduction of code under arch/arm, then that will be good.
What I don't want to see at the moment is arch/arm increasing in size as
a result of any change. We desperately need to see a reduction for the
next merge window.
Hi Russell,
> We desperately need to see a reduction for the next merge window.
I can put it all on one line if you like :D
Jeremy
On Thu, 2011-04-14 at 11:00 +0100, Russell King - ARM Linux wrote:
>
> I will take it, but at the moment I'm rather unhappy about the response
> from the community to Linus' complaint.
>
> If existing platform maintainers can show that moving over to this will
> result in a net reduction of code under arch/arm, then that will be good.
> What I don't want to see at the moment is arch/arm increasing in size as
> a result of any change. We desperately need to see a reduction for the
> next merge window.
It's a chicken and egg... platform maintainers wait for you to take it
and you wait for them to take it :-)
It seems to me that this fits well into the category of "better common
abstractions" that was discussed in the thread initiated by Linus as one
of the ways to improve on the "clutter"...
Cheers,
Ben.
On Thu, Apr 14, 2011 at 06:23:04PM +0800, Jeremy Kerr wrote:
> Hi Russell,
>
> > We desperately need to see a reduction for the next merge window.
>
> I can put it all on one line if you like :D
Yea, do that and send it to Linus for his review. I suggest a visit your
local fire department to borrow some of their protective equipment first.
:-P
On Thu, Apr 14, 2011 at 08:25:05PM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2011-04-14 at 11:00 +0100, Russell King - ARM Linux wrote:
> >
> > I will take it, but at the moment I'm rather unhappy about the response
> > from the community to Linus' complaint.
> >
> > If existing platform maintainers can show that moving over to this will
> > result in a net reduction of code under arch/arm, then that will be good.
> > What I don't want to see at the moment is arch/arm increasing in size as
> > a result of any change. We desperately need to see a reduction for the
> > next merge window.
>
> It's a chicken and egg... platform maintainers wait for you to take it
> and you wait for them to take it :-)
>
> It seems to me that this fits well into the category of "better common
> abstractions" that was discussed in the thread initiated by Linus as one
> of the ways to improve on the "clutter"...
That depends - sometimes creating generic stuff results in a net increase
in the overall size, and that's something that Linus also complained about.
According to linux-next, where we are at the moment with arch/arm is a
net increase of 6000 lines since the close of the last merge window,
and arch/arm is responsible for almost 75% of arch/ changes. It looks
very much like the same situation which Linus complained about.
Can arch/arm continue to increase in size? I think not. We desperately
need patches which reduce the size of arch/arm, and we desperately need
them *now*.
On Thu, 14 Apr 2011, Russell King - ARM Linux wrote:
> On Thu, Apr 14, 2011 at 08:25:05PM +1000, Benjamin Herrenschmidt wrote:
> > On Thu, 2011-04-14 at 11:00 +0100, Russell King - ARM Linux wrote:
> > >
> > > I will take it, but at the moment I'm rather unhappy about the response
> > > from the community to Linus' complaint.
> > >
> > > If existing platform maintainers can show that moving over to this will
> > > result in a net reduction of code under arch/arm, then that will be good.
> > > What I don't want to see at the moment is arch/arm increasing in size as
> > > a result of any change. We desperately need to see a reduction for the
> > > next merge window.
> >
> > It's a chicken and egg... platform maintainers wait for you to take it
> > and you wait for them to take it :-)
> >
> > It seems to me that this fits well into the category of "better common
> > abstractions" that was discussed in the thread initiated by Linus as one
> > of the ways to improve on the "clutter"...
>
> That depends - sometimes creating generic stuff results in a net increase
> in the overall size, and that's something that Linus also complained about.
>
> According to linux-next, where we are at the moment with arch/arm is a
> net increase of 6000 lines since the close of the last merge window,
> and arch/arm is responsible for almost 75% of arch/ changes. It looks
> very much like the same situation which Linus complained about.
Quoting Linus:
| Umm. The whole "number of lines of code" thing has become a total red
| herring.
|
| THAT IS NOT WHY I STARTED TO COMPLAIN!
|
| The reason I point out the number of lines of code is because it's one
| of the more obvious _symptoms_ of the problem.
So we need to work on infrastructure, and the clock API is exactly that.
Obviously adding it will increase the number of lines of code initially,
but eventually this will help _reduce_ them, and more importantly it
will allow for the reduction of mindless duplication of code that was
identified as being the actual problem causing maintenance pain.
Nicolas
On Thu, Apr 14, 2011 at 07:59:58AM -0400, Nicolas Pitre wrote:
> On Thu, 14 Apr 2011, Russell King - ARM Linux wrote:
>
> > On Thu, Apr 14, 2011 at 08:25:05PM +1000, Benjamin Herrenschmidt wrote:
> > > On Thu, 2011-04-14 at 11:00 +0100, Russell King - ARM Linux wrote:
> > > >
> > > > I will take it, but at the moment I'm rather unhappy about the response
> > > > from the community to Linus' complaint.
> > > >
> > > > If existing platform maintainers can show that moving over to this will
> > > > result in a net reduction of code under arch/arm, then that will be good.
> > > > What I don't want to see at the moment is arch/arm increasing in size as
> > > > a result of any change. We desperately need to see a reduction for the
> > > > next merge window.
> > >
> > > It's a chicken and egg... platform maintainers wait for you to take it
> > > and you wait for them to take it :-)
> > >
> > > It seems to me that this fits well into the category of "better common
> > > abstractions" that was discussed in the thread initiated by Linus as one
> > > of the ways to improve on the "clutter"...
> >
> > That depends - sometimes creating generic stuff results in a net increase
> > in the overall size, and that's something that Linus also complained about.
> >
> > According to linux-next, where we are at the moment with arch/arm is a
> > net increase of 6000 lines since the close of the last merge window,
> > and arch/arm is responsible for almost 75% of arch/ changes. It looks
> > very much like the same situation which Linus complained about.
>
> Quoting Linus:
>
> | Umm. The whole "number of lines of code" thing has become a total red
> | herring.
> |
> | THAT IS NOT WHY I STARTED TO COMPLAIN!
> |
> | The reason I point out the number of lines of code is because it's one
> | of the more obvious _symptoms_ of the problem.
>
> So we need to work on infrastructure, and the clock API is exactly that.
> Obviously adding it will increase the number of lines of code initially,
> but eventually this will help _reduce_ them, and more importantly it
> will allow for the reduction of mindless duplication of code that was
> identified as being the actual problem causing maintenance pain.
Adding it without anyone using it doesn't solve anything. We need
people to commit to producing patches to use it for the next merge
window.
And if you think its not about lines of code - grab the current linux-next
tree and look at the diff between v2.6.39-rc1 and master for arch/arm, and
then tell me whether using LOC is unreasonable given the patch content.
* Jeremy Kerr <[email protected]> [110303 08:39]:
>
> Platforms can enable the generic struct clock through
> CONFIG_USE_COMMON_STRUCT_CLK. In this case, the clock infrastructure
> consists of a common struct clk:
>
> struct clk {
> const struct clk_ops *ops;
> unsigned int enable_count;
> unsigned int prepare_count;
> spinlock_t enable_lock;
> struct mutex prepare_lock;
> };
>
> And a set of clock operations (defined per type of clock):
>
> struct clk_ops {
> int (*enable)(struct clk *);
> void (*disable)(struct clk *);
> unsigned long (*get_rate)(struct clk *);
> [...]
> };
>
> To define a hardware-specific clock, machine code can "subclass" the
> struct clock into a new struct (adding any device-specific data), and
> provide a set of operations:
>
> struct clk_foo {
> struct clk clk;
> void __iomem *some_register;
> };
>
> struct clk_ops clk_foo_ops = {
> .get_rate = clk_foo_get_rate,
> };
Anybody looked into passing the clock register and type
from device tree?
To me it looks like the above would allow doing that
pretty easily while avoiding duplicating all the
data from devicetree into struct clk_foo.
Tony
On Thu, 14 Apr 2011, Russell King - ARM Linux wrote:
> On Thu, Apr 14, 2011 at 07:59:58AM -0400, Nicolas Pitre wrote:
> > Quoting Linus:
> >
> > | Umm. The whole "number of lines of code" thing has become a total red
> > | herring.
> > |
> > | THAT IS NOT WHY I STARTED TO COMPLAIN!
> > |
> > | The reason I point out the number of lines of code is because it's one
> > | of the more obvious _symptoms_ of the problem.
> >
> > So we need to work on infrastructure, and the clock API is exactly that.
> > Obviously adding it will increase the number of lines of code initially,
> > but eventually this will help _reduce_ them, and more importantly it
> > will allow for the reduction of mindless duplication of code that was
> > identified as being the actual problem causing maintenance pain.
>
> Adding it without anyone using it doesn't solve anything. We need
> people to commit to producing patches to use it for the next merge
> window.
People are simply waiting for the API to hit some upstream tree (like
yours) before committing to it. You would be in a much better position
if those patches are in your tree, so that you can tell people: "Here's
the Git branch with the API in it, so now I'm expecting patches to
convert clock users to it".
> And if you think its not about lines of code - grab the current linux-next
> tree and look at the diff between v2.6.39-rc1 and master for arch/arm, and
> then tell me whether using LOC is unreasonable given the patch content.
I might have a look later. However it is clear that the ARM tree will
_never_ be as small as, say, X86 or even PPC given the indisputable
amount of hardware variations within the ARM landscape that is not to be
seen anywhere else. Until the ARM ecosystem converge towards a single
whole-system architecture we won't be able to match X86 in terms of code
reduction. Anyone thinking otherwise is living in a different universe.
However we can and must do better in consolidation work in order to make
the tree more maintainable of course. _That_ is the real issue and
_that_ is what the ARM tree sucks at. The fact that this consolidation
work might reduce the size of the ARM code is only a side effect, not
the primary goal. So let's not get too hung up about LOC but focus on
improving the infrastructure instead.
Nicolas
On Thu, Apr 14, 2011 at 09:39:58AM -0400, Nicolas Pitre wrote:
> On Thu, 14 Apr 2011, Russell King - ARM Linux wrote:
> > Adding it without anyone using it doesn't solve anything. We need
> > people to commit to producing patches to use it for the next merge
> > window.
> People are simply waiting for the API to hit some upstream tree (like
> yours) before committing to it. You would be in a much better position
> if those patches are in your tree, so that you can tell people: "Here's
> the Git branch with the API in it, so now I'm expecting patches to
> convert clock users to it".
One way of doing this would be to apply the patches to a branch in your
tree which isn't merged into -next and request that architecture
maintainers wishing to make use of the branch pull it into their trees.
That way it'll go into -next with at least one user but multiple
architectures can still work on using it in the initial merge.
On Thu, Apr 14, 2011 at 09:39:58AM -0400, Nicolas Pitre wrote:
> I might have a look later. However it is clear that the ARM tree will
> _never_ be as small as, say, X86 or even PPC given the indisputable
> amount of hardware variations within the ARM landscape that is not to be
> seen anywhere else. Until the ARM ecosystem converge towards a single
> whole-system architecture we won't be able to match X86 in terms of code
> reduction. Anyone thinking otherwise is living in a different universe.
>
> However we can and must do better in consolidation work in order to make
> the tree more maintainable of course. _That_ is the real issue and
> _that_ is what the ARM tree sucks at. The fact that this consolidation
> work might reduce the size of the ARM code is only a side effect, not
> the primary goal. So let's not get too hung up about LOC but focus on
> improving the infrastructure instead.
Look, this is what is in amongst the 6K lines of new code - these are
the top two in the diffstat with the highest number of additional lines:
arch/arm/mach-ux500/clock-db8500.c | 1291 +++++++++++++
arch/arm/mach-ux500/prcmu-db8500.c | 2018 ++++++++++++++++++++
These comprise 50% of the 6K of new code. clock-db8500.c is a mixture
of code and data declarations for individual clocks - which is essentially
what Linus picked up with his complaint on under OMAP. That in itself
makes me worried.
Looking at the other file, prcmu-db8500.c seems to contain at least 5 sets
of mailbox support code. Take a look at "Subject: [PATCH 9/9] mach-ux500:
add DB5500 PRCMU interface" from Linus Walleij on 31st March on this list
for the patch. Are we sure that this couldn't be consolidated in some
way, at least at file level?
So while you can say about not getting hung up about LOC, LOC is a good
indication that things are still going wrong in much the same way.
On the positive note, it looks like MX3 is being merged into IMX stuff,
which is good news, and the mxc91231 has been dropped. We need to ensure
that good work like this, which will make Linus happy, doesn't get
swamped by new stuff.
We must take Linus' complaint about 'churn' seriously - it's not something
new that he's just started to complain about in the last month. It's
something which he's complained about on a number of occasions. Feel free
to think what you may about that, but just bear in mind that Linus holds
the keys to the mainline kernel, and he can put us in a different universe.
Now, the next thing is that Linus hasn't been too happy about driver stuff
coming via my tree either - it's something which has been the subject of
concern in private email. I've _already_ said something about that prior
to the recent merge window. So should I take the clk API stuff which
touches the drivers subtree? If yes, it needs to be kept entirely separate
from the rest of the ARM stuff so we don't end up mixing drivers stuff with
ARM stuff.
On Thu, 14 Apr 2011, Russell King - ARM Linux wrote:
> On Thu, Apr 14, 2011 at 09:39:58AM -0400, Nicolas Pitre wrote:
> > However we can and must do better in consolidation work in order to make
> > the tree more maintainable of course. _That_ is the real issue and
> > _that_ is what the ARM tree sucks at. The fact that this consolidation
> > work might reduce the size of the ARM code is only a side effect, not
> > the primary goal. So let's not get too hung up about LOC but focus on
> > improving the infrastructure instead.
>
> Look, this is what is in amongst the 6K lines of new code - these are
> the top two in the diffstat with the highest number of additional lines:
>
> arch/arm/mach-ux500/clock-db8500.c | 1291 +++++++++++++
> arch/arm/mach-ux500/prcmu-db8500.c | 2018 ++++++++++++++++++++
>
> These comprise 50% of the 6K of new code. clock-db8500.c is a mixture
> of code and data declarations for individual clocks - which is essentially
> what Linus picked up with his complaint on under OMAP. That in itself
> makes me worried.
Sure. So... let's see what we can do about it. Having 1300 lines only
for clock stuff on only one platform certainly looks silly. Either we
can consolidate some of that stuff with another similar-enough platform,
or we're stuck with the ST-E hardware being just too different from,
say, the OMAP clock hardware for those to be consolidated. In the
former case we can work towards a solution and that code currently in
next won't make it to mainline, or in the later case... well... we'll
have to live with it. If in doubt let's simply ask the opinion of those
mainline people who said they're willing to help with advices. If in
the end they have no better solutions than what we have now then it will
be harder for them to complain.
> Looking at the other file, prcmu-db8500.c seems to contain at least 5 sets
> of mailbox support code. Take a look at "Subject: [PATCH 9/9] mach-ux500:
> add DB5500 PRCMU interface" from Linus Walleij on 31st March on this list
> for the patch. Are we sure that this couldn't be consolidated in some
> way, at least at file level?
>
> So while you can say about not getting hung up about LOC, LOC is a good
> indication that things are still going wrong in much the same way.
Agreed. My point is, we shouldn't be afraid to add more code if that
code is allowing for some consolidation to happen down the road, which
should be the case with the initial subject of this thread.
Nicolas
On Thu, Apr 14, 2011 at 11:32:00AM +0100, Russell King - ARM Linux wrote:
> On Thu, Apr 14, 2011 at 08:25:05PM +1000, Benjamin Herrenschmidt wrote:
> > On Thu, 2011-04-14 at 11:00 +0100, Russell King - ARM Linux wrote:
> > >
> > > I will take it, but at the moment I'm rather unhappy about the response
> > > from the community to Linus' complaint.
> > >
> > > If existing platform maintainers can show that moving over to this will
> > > result in a net reduction of code under arch/arm, then that will be good.
> > > What I don't want to see at the moment is arch/arm increasing in size as
> > > a result of any change. We desperately need to see a reduction for the
> > > next merge window.
> >
> > It's a chicken and egg... platform maintainers wait for you to take it
> > and you wait for them to take it :-)
> >
> > It seems to me that this fits well into the category of "better common
> > abstractions" that was discussed in the thread initiated by Linus as one
> > of the ways to improve on the "clutter"...
>
> That depends - sometimes creating generic stuff results in a net increase
> in the overall size, and that's something that Linus also complained about.
>
> According to linux-next, where we are at the moment with arch/arm is a
> net increase of 6000 lines since the close of the last merge window,
> and arch/arm is responsible for almost 75% of arch/ changes. It looks
> very much like the same situation which Linus complained about.
Well, looking at the output of
git diff --dirstat=3 linus/master...next/master -- arch
(with linus/master == 85f2e689a and next/master == 9e06a6ea7) I think
the main culprit is 12dc7eff5 that moved arch/arm/mach-mx3 to
arch/arm/mach-imx. (75 files changed, 9783 insertions(+), 9731
deletions(-)) That's a part of the effort to consolidate the i.MX
platforms and allow to compile more SoCs in a single image.
That commit accounts for more than the half of the (loc) changes in
arch/arm.
OK, this doesn't discuss away the 6000 added lines, but at least the
percentage thingy. And I think when you point out this commit Linus will
be much quiter when replying to your pull request.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Hello,
On Thu, Apr 14, 2011 at 04:38:14PM +0100, Russell King - ARM Linux wrote:
> On Thu, Apr 14, 2011 at 09:39:58AM -0400, Nicolas Pitre wrote:
> Now, the next thing is that Linus hasn't been too happy about driver stuff
> coming via my tree either - it's something which has been the subject of
> concern in private email. I've _already_ said something about that prior
> to the recent merge window. So should I take the clk API stuff which
> touches the drivers subtree? If yes, it needs to be kept entirely separate
> from the rest of the ARM stuff so we don't end up mixing drivers stuff with
> ARM stuff.
OK, so the solution is to put this in a seperate branch. But then when
platform maintainers start working with it the resulting changes will
most probably go to arch/arm. So if Linus doesn't want to pull a tree
that touches both drivers/clk and arch/arm, then either he has to pull
the clk branch first or we have to wait for the next merge window until
we can use it.
I prefer the former.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On 04/14/2011 05:09 AM, Russell King - ARM Linux wrote:
> On Thu, Apr 14, 2011 at 07:59:58AM -0400, Nicolas Pitre wrote:
>> On Thu, 14 Apr 2011, Russell King - ARM Linux wrote:
>>
>>> On Thu, Apr 14, 2011 at 08:25:05PM +1000, Benjamin Herrenschmidt wrote:
>>>> On Thu, 2011-04-14 at 11:00 +0100, Russell King - ARM Linux wrote:
>>>>>
>>>>> I will take it, but at the moment I'm rather unhappy about the response
>>>>> from the community to Linus' complaint.
>>>>>
>>>>> If existing platform maintainers can show that moving over to this will
>>>>> result in a net reduction of code under arch/arm, then that will be good.
>>>>> What I don't want to see at the moment is arch/arm increasing in size as
>>>>> a result of any change. We desperately need to see a reduction for the
>>>>> next merge window.
>>>>
>>>> It's a chicken and egg... platform maintainers wait for you to take it
>>>> and you wait for them to take it :-)
>>>>
>>>> It seems to me that this fits well into the category of "better common
>>>> abstractions" that was discussed in the thread initiated by Linus as one
>>>> of the ways to improve on the "clutter"...
>>>
>>> That depends - sometimes creating generic stuff results in a net increase
>>> in the overall size, and that's something that Linus also complained about.
>>>
>>> According to linux-next, where we are at the moment with arch/arm is a
>>> net increase of 6000 lines since the close of the last merge window,
>>> and arch/arm is responsible for almost 75% of arch/ changes. It looks
>>> very much like the same situation which Linus complained about.
>>
>> Quoting Linus:
>>
>> | Umm. The whole "number of lines of code" thing has become a total red
>> | herring.
>> |
>> | THAT IS NOT WHY I STARTED TO COMPLAIN!
>> |
>> | The reason I point out the number of lines of code is because it's one
>> | of the more obvious _symptoms_ of the problem.
>>
>> So we need to work on infrastructure, and the clock API is exactly that.
>> Obviously adding it will increase the number of lines of code initially,
>> but eventually this will help _reduce_ them, and more importantly it
>> will allow for the reduction of mindless duplication of code that was
>> identified as being the actual problem causing maintenance pain.
>
> Adding it without anyone using it doesn't solve anything. We need
> people to commit to producing patches to use it for the next merge
> window.
Russell,
In your first reply to Jeremy you said this:
"I will take it, but at the moment I'm rather unhappy about the response
from the community to Linus' complaint."
So, if you are going to pull in his patches for the next merge, you can
ignore this most of this email.
Talking for MSM, I'm waiting for some kind of certainty that these APIs
will not be changed again before I rework our clock code to it. Even if
I decide to move to this new framework without that certainty, it's
going to be hard to convince driver teams to start using this new API if
it's not already accepted upstream. At which point we would be back to
square one -- "we need to see drivers (clock consumers) use these new
APIs/rework before we pull it in".
Long story short, it's exactly the chicken and egg problem Nicolas was
talking about and we need to break the egg :-)
Also, Jeremy's changes are more than just consolidation. They add
clk_prepare/clk_unprepare APIs and those would be quite beneficial to
quite a few machs/archs.
> And if you think its not about lines of code - grab the current linux-next
> tree and look at the diff between v2.6.39-rc1 and master for arch/arm, and
> then tell me whether using LOC is unreasonable given the patch content.
I'm sure lines of code is important, but saying we won't add any
architectural improvements because it adds LOC seems backwards. If we go
by that policy, the end result would be a freeze of the kernel.
Btw, what's your position on device tree for ARM? Device tree should
help out a lot with clock data taking up too many LOCs.
Thanks,
Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Thu, Apr 14, 2011 at 04:38:14PM +0100, Russell King - ARM Linux wrote:
> On Thu, Apr 14, 2011 at 09:39:58AM -0400, Nicolas Pitre wrote:
> > However we can and must do better in consolidation work in order to make
> > the tree more maintainable of course. _That_ is the real issue and
> > _that_ is what the ARM tree sucks at. The fact that this consolidation
> > work might reduce the size of the ARM code is only a side effect, not
> > the primary goal. So let's not get too hung up about LOC but focus on
> > improving the infrastructure instead.
>
> Look, this is what is in amongst the 6K lines of new code - these are
> the top two in the diffstat with the highest number of additional lines:
>
> arch/arm/mach-ux500/clock-db8500.c | 1291 +++++++++++++
> arch/arm/mach-ux500/prcmu-db8500.c | 2018 ++++++++++++++++++++
>
> These comprise 50% of the 6K of new code. clock-db8500.c is a mixture
> of code and data declarations for individual clocks - which is essentially
> what Linus picked up with his complaint on under OMAP. That in itself
> makes me worried.
>
A common struct clk implementation will at least allow you to whittle
this number down a bit, but it's obviously not possible to attempt to
work with the generic infrastructure prior to it being merged. Given that
there is nothing ARM-specific about the patch series it doesn't much
matter which tree it ultimately gets merged through, so long as it's in
place for people to build on top of for the next merge window.
> Now, the next thing is that Linus hasn't been too happy about driver stuff
> coming via my tree either - it's something which has been the subject of
> concern in private email. I've _already_ said something about that prior
> to the recent merge window. So should I take the clk API stuff which
> touches the drivers subtree? If yes, it needs to be kept entirely separate
> from the rest of the ARM stuff so we don't end up mixing drivers stuff with
> ARM stuff.
ARM has been the defacto owner for the clock bits to date, but between
clkdev and a common struct clk it's certainly possible to move to a clock
tree and treat it the same as any other subsystem. Moving things out of
arch/arm and in to more generic maintenance paths certainly reduces the
chance for abuse -- and also provides a path for driver stuff.
SH and ARM-based SH/R-Mobile CPUs already share a clock framework, which
I've slowly been refactoring in preparation for Jeremy's common struct
clk. With that merged I'll be able to kill off a couple hundred lines
from the existing implementation at least.
If you'd prefer not to be the guinea pig for the clock bits going in to
.40 I'm certainly happy to take them in a topic branch, convert my
platforms on top of that and send the bits off to Linus early in the
merge window.
Hello,
On Mon, Apr 18, 2011 at 07:54:42PM +0900, Paul Mundt wrote:
> If you'd prefer not to be the guinea pig for the clock bits going in to
> .40 I'm certainly happy to take them in a topic branch, convert my
> platforms on top of that and send the bits off to Linus early in the
> merge window.
To get this forward I set up a branch with the generic bits sent to the
list so far. I really think this should be fixed better now than later
to give enough time for potential users of the new API to implement it
for their platform.
The following changes since commit f0e615c3cb72b42191b558c130409335812621d8:
Linux 2.6.39-rc4 (2011-04-18 21:26:00 -0700)
are available in the git repository at:
git://git.pengutronix.de/git/ukl/linux-2.6.git common-struct-clk
Jeremy Kerr (2):
Add a common struct clk
clk: Generic support for fixed-rate clocks
Russell King - ARM Linux (1):
Fix clkdev return value for NULL clk case
Sascha Hauer (1):
clk: Make NULL a valid clock again
drivers/clk/Kconfig | 3 +
drivers/clk/Makefile | 1 +
drivers/clk/clk.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/clkdev.c | 26 +++++---
include/linux/clk.h | 180 +++++++++++++++++++++++++++++++++++++++++++++++---
5 files changed, 364 insertions(+), 19 deletions(-)
create mode 100644 drivers/clk/clk.c
I declare this to be stable, so assuming people are OK with it, you can
use that as a base to convert your platforms.
@Linus: I hope you're willing to pull this branch after .39?! (A public
"yes" might motivate one or the other maintainer to convert their
platform to it.)
There is a 2nd branch on that repository that also contains my RFC patch
just sent to this list in case you want to test it.
The following changes since commit 0ddb7f510fd51213801bf33194629fabf0818f39:
clk: Make NULL a valid clock again (2011-04-20 16:02:29 +0200)
are available in the git repository at:
git://git.pengutronix.de/git/ukl/linux-2.6.git common-struct-clk-wip
Uwe Kleine-K?nig (1):
[RFC] clk: add support for automatic parent handling
drivers/clk/clk.c | 43 +++++++++++++++++++++++++++++++++++++++++++
include/linux/clk.h | 8 ++++++++
2 files changed, 51 insertions(+), 0 deletions(-)
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-K?nig |
Industrial Linux Solutions | http://www.pengutronix.de/ |
On Wed, 20 Apr 2011, Uwe Kleine-K?nig wrote:
> I declare this to be stable, so assuming people are OK with it, you can
> use that as a base to convert your platforms.
You declare that stable? Interesting.
> There is a 2nd branch on that repository that also contains my RFC patch
> just sent to this list in case you want to test it.
Which is utter crap as I pointed out a few minutes ago.
Also that clk thing is neither stable nor complete. It's just designed
wrong.
As long as it does not handle nested clocks proper and by default w/o
your tasteless add ons, it's just moving the status quo of ARM into a
common infrastructure file.
Yes, that's probably better than not having common infrastructure at
all, but trying to build up conversions on that lot would be a
complete waste of time and resources. Simply because you need to
convert the already converted stuff another time.
Thanks,
tglx