diff mbox

[3/4] clk: Provide always-on clock support

Message ID 1425071674-16995-4-git-send-email-lee.jones@linaro.org
State New
Headers show

Commit Message

Lee Jones Feb. 27, 2015, 9:14 p.m. UTC
Lots of platforms contain clocks which if turned off would prove fatal.
The only way to recover from these catastrophic failures is to restart
the board(s).  Now, when a clock is registered with the framework it is
compared against a list of provided always-on clock names which must be
kept ungated.  If it matches, we enable the existing CLK_IGNORE_UNUSED
flag, which will prevent the common clk framework from attempting to
gate it during the clk_disable_unused() procedure.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/clk/clk.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

Comments

Lee Jones Feb. 27, 2015, 9:51 p.m. UTC | #1
On Fri, 27 Feb 2015, Lee Jones wrote:

> Lots of platforms contain clocks which if turned off would prove fatal.
> The only way to recover from these catastrophic failures is to restart
> the board(s).  Now, when a clock is registered with the framework it is
> compared against a list of provided always-on clock names which must be
> kept ungated.  If it matches, we enable the existing CLK_IGNORE_UNUSED
> flag, which will prevent the common clk framework from attempting to
> gate it during the clk_disable_unused() procedure.
> 
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
>  drivers/clk/clk.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 61c3fc5..3aab75e 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -2856,6 +2856,9 @@ int of_clk_add_provider(struct device_node *np,
>  			void *data)
>  {
>  	struct of_clk_provider *cp;
> +	struct property *prop;
> +	struct clk *clk;
> +	const char *clkname;
>  	int ret;
>  
>  	cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
> @@ -2875,6 +2878,14 @@ int of_clk_add_provider(struct device_node *np,
>  	if (ret < 0)
>  		of_clk_del_provider(np);
>  
> +	of_property_for_each_string(np, "clock-always-on", prop, clkname) {
> +		clk = __clk_lookup(clkname);
> +		if (!clk)
> +			continue;
> +
> +		clk->core->flags |= CLK_IGNORE_UNUSED;

Might save a few cycles by breaking here.

> +	}
> +
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(of_clk_add_provider);
Jassi Brar Feb. 28, 2015, 9:21 a.m. UTC | #2
On 28 February 2015 at 02:44, Lee Jones <lee.jones@linaro.org> wrote:
> Lots of platforms contain clocks which if turned off would prove fatal.
> The only way to recover from these catastrophic failures is to restart
> the board(s).  Now, when a clock is registered with the framework it is
> compared against a list of provided always-on clock names which must be
> kept ungated.  If it matches, we enable the existing CLK_IGNORE_UNUSED
> flag, which will prevent the common clk framework from attempting to
> gate it during the clk_disable_unused() procedure.
>
If a clock is critical on a certain board, it could be got+enabled
during early boot so there is always a user.
To be able to do that from DT, maybe add a new, say, CLK_ALWAYS_ON
flag could be made to initialize the clock with one phantom user
already. Or just reuse the CLK_IGNORE_UNUSED?

-Jassi
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lee Jones March 2, 2015, 8:16 a.m. UTC | #3
On Sat, 28 Feb 2015, Maxime Coquelin wrote:

> Hi Lee,
> 
> On 02/27/2015 10:14 PM, Lee Jones wrote:
> >Lots of platforms contain clocks which if turned off would prove fatal.
> >The only way to recover from these catastrophic failures is to restart
> >the board(s).  Now, when a clock is registered with the framework it is
> >compared against a list of provided always-on clock names which must be
> >kept ungated.  If it matches, we enable the existing CLK_IGNORE_UNUSED
> >flag, which will prevent the common clk framework from attempting to
> >gate it during the clk_disable_unused() procedure.
> 
> Please correct me if I'm wrong, but your patch does not fix the
> issue you had initially.
> Let's take an example:
> A clock is critical for the system, and should never be gated, so
> you add the CLK_IGNORE_UNUSED
> flag so that it is not disabled by clk_disable_unused() procedure.
> The same clock is also used by other IPs, for example spi 0 instance.
> When starting a spi transfer, clk_enable() is called on this clock,
> so its usecount becomes 1.
> Once transfer done, clk_disable() is called, usecount becomes 0 and
> the clock gets disabled: system freeze.

You're right.  I also need to extend clk_core_disable() to take notice
of CLK_IGNORE_UNUSED.
Lee Jones March 2, 2015, 8:36 a.m. UTC | #4
On Sat, 28 Feb 2015, Jassi Brar wrote:

> On 28 February 2015 at 02:44, Lee Jones <lee.jones@linaro.org> wrote:
> > Lots of platforms contain clocks which if turned off would prove fatal.
> > The only way to recover from these catastrophic failures is to restart
> > the board(s).  Now, when a clock is registered with the framework it is
> > compared against a list of provided always-on clock names which must be
> > kept ungated.  If it matches, we enable the existing CLK_IGNORE_UNUSED
> > flag, which will prevent the common clk framework from attempting to
> > gate it during the clk_disable_unused() procedure.
> >
> If a clock is critical on a certain board, it could be got+enabled
> during early boot so there is always a user.

I tried this.  There was push-back from the DT maintainers.

  http://lists.infradead.org/pipermail/linux-arm-kernel/2015-February/324417.html

> To be able to do that from DT, maybe add a new, say, CLK_ALWAYS_ON
> flag could be made to initialize the clock with one phantom user
> already. Or just reuse the CLK_IGNORE_UNUSED?

How is that different to what this set is doing?
diff mbox

Patch

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 61c3fc5..3aab75e 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2856,6 +2856,9 @@  int of_clk_add_provider(struct device_node *np,
 			void *data)
 {
 	struct of_clk_provider *cp;
+	struct property *prop;
+	struct clk *clk;
+	const char *clkname;
 	int ret;
 
 	cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
@@ -2875,6 +2878,14 @@  int of_clk_add_provider(struct device_node *np,
 	if (ret < 0)
 		of_clk_del_provider(np);
 
+	of_property_for_each_string(np, "clock-always-on", prop, clkname) {
+		clk = __clk_lookup(clkname);
+		if (!clk)
+			continue;
+
+		clk->core->flags |= CLK_IGNORE_UNUSED;
+	}
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(of_clk_add_provider);