From: Jeremy Kerr <jeremy.kerr@canonical.com>
To: linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 0/3] Common struct clk implementation, v7
Date: Thu, 16 Sep 2010 08:19:24 +0000 [thread overview]
Message-ID: <1284625164.3350.62.camel@pororo> (raw)
In-Reply-To: <AANLkTim++mNF=KDabCBCk=jDxbwNFWu=hrDQq=UWR=yM@mail.gmail.com>
Hi Colin,
> Having just finished implementing the clock tree support on Tegra, I
> have a few concerns about these patches, and how they relate to the
> clk api.
>
Thanks for taking a look through the patches - I'm definitely keen to
hear more from those doing implementations of either clock API.
> On the spinlock vs. mutex issue (I know, it's been beaten to death).
I wouldn't say beaten to death, I just haven't heard a good case for the
atomic lock option yet (well, until your email..) :)
> The clk api does not specify whether or not implementations can sleep.
> In fact, it explicitly states that clk_get and clk_put can't be
> called from atomic context, but does not say anything about the rest
> of the api, which vaguely implies that they can be called from atomic
> context.
At present, clk_enable and clk_disable can only be called from
non-atomic contexts.
All other operations can be called from atomic contexts, *provided that*
the underlying clock implementation does not block. I'm not planning to
enforce any rules about the implementations, so this will probably stay
as an "it depends".
> There are situations in which a non-sleeping clk api is useful, if not
> necessary. On msm with a smart panel, the vsync is connected to a
> gpio, and the vsync interrupt enables the dma controller clock is to
> start the dma of the framebuffer to the display block. A similar
> problem can happen in dma audio, where a low watermark interrupt from
> the audio block needs to trigger dma to refill the buffer.
Just to clarify - these two examples definitely can't defer the enable,
right?
> Because of the refcounting in
> clk_disable, this is not particularly difficult, but a
> clk_disable_later helper function might simplify it.
Sounds reasonable; something like clk_disable_later would be good.
> Additionally, using a lock per clk struct can cause AB-BA locking
> issues. In my implementation, calling clk_enable on a child clock in
> the clock tree can call clk_enable on its parent if the child clock
> was not already enabled.
Yep, and my implementation does the same.
> This leads to the child clock lock being
> taken, followed by the parent clock lock. Calling clk_set_rate on the
> parent requires recalculating the rate of all of the children, which
> leads to the parent clock lock being taken first, followed by the
> child clock lock. Deadlock.
I don't currently enforce any locking in set_rate; if a clock
implementation does locking in this order (child before parent), then
it'd have to use a separate lock, rather than acquiring the clk->mutex
in the set_rate operation.
> I solved these problems by using a single spinlock around all of the
> clocks, plus an additional mutex around the clocks that need to sleep.
> I also locally added clk_*_cansleep functions to the clk api, and
> used might_sleep to prevent calls to the non-cansleep clk api on
> clocks that require sleeping. I'm not happy with this solution, as it
> uses a local extension to a cross-platform api, but I don't see any
> way around it. Some clocks really need to be enabled or disabled from
> atomic context, and some clocks are impossible to use in atomic
> context.
>
> I think something a little like the gpio api style of cansleep and non
> cansleep functions would help would preserve the ability for clocks to
> avoid sleeping on platforms that don't need to sleep, while allowing
> drivers that can handle sleeping clocks to remain as widely
> cross-platform as possible. Instead of changing all the calls, add a
> clk_get_nosleep for drivers that will call the clk apis in atomic
> context, which will catch drivers that are not compatible with the
> clock they are requesting early on during probe.
>
> Either way, the clk api could use some notes on the restrictions for
> both the callers and the implementers to ensure compatibility between
> architectures.
Yes, agreed.
Basically, the reason for choosing a mutex rather than a spinlock is
based on how easy it is to workaround and use it in the "other" context;
ie, how we can use a mutex-based clock in an atomic environment, or use
a spinlock in a non-atomic environment.
With the mutex-based clock, enabling from a atomic environment means
that the callee needs to defer work to non-atomic context, a fairly
standard design pattern which (up until your email) I thought would
cater for all cases.
With a spinlock-based clock, the callee does not need to defer any work,
but it means that the clock implementation needs to enable/disable the
clock atomically. For clock implementations that need to sleep, we can
defer the enabling, but this means that clk_enable() returns before the
clock is actually enabled, which is not acceptable.
If we really do need both locking semantics, it'd be ugly, we could do
something like:
struct clk {
union {
struct mutex mutex;
spintlock_t spinlock;
} lock;
const struct clk_ops *ops;
[...]
};
struct clk_ops {
void (*lock)(struct clk *clk);
void (*unlock)(struct clk *clk);
[ existing clk_ops function pointers ]
};
And provide the corresponding implementations for lock/unlock:
void clk_mutex_lock(struct clk *clk)
{
mutex_acquire(&clk->lock.mutex);
}
void clk_spinlock_lock(struct clk *clk)
{
spin_lock(&clk->lock.spinlock);
}
void clk_noop_lock(struct clk *clk)
{
}
Then the implementation can choose the appropriate lock for the clock,
based on whether it needs to sleep to enable & disable. The core code
would then call clk->lock() and clk->unlock() instead of manipulating
clk->mutex directly.
[I've used a union for clarity here - we'd need to do some trickery to
properly initialise the clock's lock statically, or we could drop the
union and steal the mutex's spinlock for the atomic case]
The big downside of this is that the locking semantics are no longer
obvious to the device driver API, which may be getting an atomic clock
or a non-atomic one. As you suggest, we could add a helper:
clk_get_atomic()
- which would just do a clk_get() and then BUG_ON() if we have the wrong
type.
Any thoughts?
Cheers,
Jeremy
next prev parent reply other threads:[~2010-09-16 8:19 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1284522014.516876.675872472687.0.gpush@pororo>
2010-09-15 5:53 ` [PATCH 0/3] Common struct clk implementation, v7 Jean-Christophe PLAGNIOL-VILLARD
2010-09-15 6:08 ` Jeremy Kerr
2010-09-16 1:51 ` Paul Mundt
2010-09-15 23:15 ` Colin Cross
2010-09-16 8:19 ` Jeremy Kerr [this message]
2010-09-26 23:57 ` Ben Dooks
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1284625164.3350.62.camel@pororo \
--to=jeremy.kerr@canonical.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).