diff mbox

[v2] clk: exynos5420: Keep aclk66_peric enabled during boot

Message ID 1401467562-5585-1-git-send-email-dianders@chromium.org (mailing list archive)
State New, archived
Headers show

Commit Message

Doug Anderson May 30, 2014, 4:32 p.m. UTC
Right now if you've got earlyprintk enabled on exynos5420-peach-pit
then you'll get a hang on boot.  Here's why:

1. The i2c-s3c2410 driver will probe at subsys_initcall.  It will
   enable its clock and disable it.  This is the clock "i2c2".
2. The act of disabling "i2c2" will disable its parents.  In this case
   the parent is "aclk66_peric".  There are no other children of
   "aclk66_peric" officially enabled, so "aclk66_peric" will be turned
   off (despite being CLK_IGNORE_UNUSED, but that's by design).
3. The next time you try to earlyprintk you'll do so without the UART
   clock enabled.  That's because the UART clocks are also children of
   "aclk66_peric".  You'll hang.

There's no good place to put a clock enable for earlyprintk, which is
handled by a bunch of assembly code.  The best we can do is to handle
this in the clock driver.

Signed-off-by: Doug Anderson <dianders@chromium.org>
Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
---
Changes in v2:
- Use GATE_A and clk_get().  Save the clock for putting later.
- Return 0 from exynos5420_clk_late_init().

 drivers/clk/samsung/clk-exynos5420.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

Comments

Doug Anderson June 5, 2014, 6:48 p.m. UTC | #1
Tomasz / Mike,

On Fri, May 30, 2014 at 9:32 AM, Doug Anderson <dianders@chromium.org> wrote:
> Right now if you've got earlyprintk enabled on exynos5420-peach-pit
> then you'll get a hang on boot.  Here's why:
>
> 1. The i2c-s3c2410 driver will probe at subsys_initcall.  It will
>    enable its clock and disable it.  This is the clock "i2c2".
> 2. The act of disabling "i2c2" will disable its parents.  In this case
>    the parent is "aclk66_peric".  There are no other children of
>    "aclk66_peric" officially enabled, so "aclk66_peric" will be turned
>    off (despite being CLK_IGNORE_UNUSED, but that's by design).
> 3. The next time you try to earlyprintk you'll do so without the UART
>    clock enabled.  That's because the UART clocks are also children of
>    "aclk66_peric".  You'll hang.
>
> There's no good place to put a clock enable for earlyprintk, which is
> handled by a bunch of assembly code.  The best we can do is to handle
> this in the clock driver.
>
> Signed-off-by: Doug Anderson <dianders@chromium.org>
> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
> Changes in v2:
> - Use GATE_A and clk_get().  Save the clock for putting later.
> - Return 0 from exynos5420_clk_late_init().
>
>  drivers/clk/samsung/clk-exynos5420.c | 33 +++++++++++++++++++++++++++++++--
>  1 file changed, 31 insertions(+), 2 deletions(-)

Are there other changes you'd like me to make to this?  It would be
really nice to get this in for 3.16 so the system doesn't just
mysteriously hang when you use earlyprintk.

-Doug
Tomasz Figa June 5, 2014, 7:14 p.m. UTC | #2
On 05.06.2014 20:48, Doug Anderson wrote:
> Tomasz / Mike,
> 
> On Fri, May 30, 2014 at 9:32 AM, Doug Anderson <dianders@chromium.org> wrote:
>> Right now if you've got earlyprintk enabled on exynos5420-peach-pit
>> then you'll get a hang on boot.  Here's why:
>>
>> 1. The i2c-s3c2410 driver will probe at subsys_initcall.  It will
>>    enable its clock and disable it.  This is the clock "i2c2".
>> 2. The act of disabling "i2c2" will disable its parents.  In this case
>>    the parent is "aclk66_peric".  There are no other children of
>>    "aclk66_peric" officially enabled, so "aclk66_peric" will be turned
>>    off (despite being CLK_IGNORE_UNUSED, but that's by design).
>> 3. The next time you try to earlyprintk you'll do so without the UART
>>    clock enabled.  That's because the UART clocks are also children of
>>    "aclk66_peric".  You'll hang.
>>
>> There's no good place to put a clock enable for earlyprintk, which is
>> handled by a bunch of assembly code.  The best we can do is to handle
>> this in the clock driver.
>>
>> Signed-off-by: Doug Anderson <dianders@chromium.org>
>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>> ---
>> Changes in v2:
>> - Use GATE_A and clk_get().  Save the clock for putting later.
>> - Return 0 from exynos5420_clk_late_init().
>>
>>  drivers/clk/samsung/clk-exynos5420.c | 33 +++++++++++++++++++++++++++++++--
>>  1 file changed, 31 insertions(+), 2 deletions(-)
> 
> Are there other changes you'd like me to make to this?  It would be
> really nice to get this in for 3.16 so the system doesn't just
> mysteriously hang when you use earlyprintk.

We can probably take this as an -rc fix, so it should be fine.

However I still don't see the point of exporting this clock and
polluting the global clkdev namespace. Even the diffstat looks better in v1.

Best regards,
Tomasz
Doug Anderson June 5, 2014, 7:22 p.m. UTC | #3
Tomasz,

On Thu, Jun 5, 2014 at 12:14 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> On 05.06.2014 20:48, Doug Anderson wrote:
>> Tomasz / Mike,
>>
>> On Fri, May 30, 2014 at 9:32 AM, Doug Anderson <dianders@chromium.org> wrote:
>>> Right now if you've got earlyprintk enabled on exynos5420-peach-pit
>>> then you'll get a hang on boot.  Here's why:
>>>
>>> 1. The i2c-s3c2410 driver will probe at subsys_initcall.  It will
>>>    enable its clock and disable it.  This is the clock "i2c2".
>>> 2. The act of disabling "i2c2" will disable its parents.  In this case
>>>    the parent is "aclk66_peric".  There are no other children of
>>>    "aclk66_peric" officially enabled, so "aclk66_peric" will be turned
>>>    off (despite being CLK_IGNORE_UNUSED, but that's by design).
>>> 3. The next time you try to earlyprintk you'll do so without the UART
>>>    clock enabled.  That's because the UART clocks are also children of
>>>    "aclk66_peric".  You'll hang.
>>>
>>> There's no good place to put a clock enable for earlyprintk, which is
>>> handled by a bunch of assembly code.  The best we can do is to handle
>>> this in the clock driver.
>>>
>>> Signed-off-by: Doug Anderson <dianders@chromium.org>
>>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>>> ---
>>> Changes in v2:
>>> - Use GATE_A and clk_get().  Save the clock for putting later.
>>> - Return 0 from exynos5420_clk_late_init().
>>>
>>>  drivers/clk/samsung/clk-exynos5420.c | 33 +++++++++++++++++++++++++++++++--
>>>  1 file changed, 31 insertions(+), 2 deletions(-)
>>
>> Are there other changes you'd like me to make to this?  It would be
>> really nice to get this in for 3.16 so the system doesn't just
>> mysteriously hang when you use earlyprintk.
>
> We can probably take this as an -rc fix, so it should be fine.
>
> However I still don't see the point of exporting this clock and
> polluting the global clkdev namespace. Even the diffstat looks better in v1.

OK, I'm happy to go back to v1 with the addition of the "return 0".

Mike: are you OK with that?
Tomasz Figa June 5, 2014, 7:31 p.m. UTC | #4
On 05.06.2014 21:22, Doug Anderson wrote:
> Tomasz,
> 
> On Thu, Jun 5, 2014 at 12:14 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
>> On 05.06.2014 20:48, Doug Anderson wrote:
>>> Tomasz / Mike,
>>>
>>> On Fri, May 30, 2014 at 9:32 AM, Doug Anderson <dianders@chromium.org> wrote:
>>>> Right now if you've got earlyprintk enabled on exynos5420-peach-pit
>>>> then you'll get a hang on boot.  Here's why:
>>>>
>>>> 1. The i2c-s3c2410 driver will probe at subsys_initcall.  It will
>>>>    enable its clock and disable it.  This is the clock "i2c2".
>>>> 2. The act of disabling "i2c2" will disable its parents.  In this case
>>>>    the parent is "aclk66_peric".  There are no other children of
>>>>    "aclk66_peric" officially enabled, so "aclk66_peric" will be turned
>>>>    off (despite being CLK_IGNORE_UNUSED, but that's by design).
>>>> 3. The next time you try to earlyprintk you'll do so without the UART
>>>>    clock enabled.  That's because the UART clocks are also children of
>>>>    "aclk66_peric".  You'll hang.
>>>>
>>>> There's no good place to put a clock enable for earlyprintk, which is
>>>> handled by a bunch of assembly code.  The best we can do is to handle
>>>> this in the clock driver.
>>>>
>>>> Signed-off-by: Doug Anderson <dianders@chromium.org>
>>>> Tested-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
>>>> ---
>>>> Changes in v2:
>>>> - Use GATE_A and clk_get().  Save the clock for putting later.
>>>> - Return 0 from exynos5420_clk_late_init().
>>>>
>>>>  drivers/clk/samsung/clk-exynos5420.c | 33 +++++++++++++++++++++++++++++++--
>>>>  1 file changed, 31 insertions(+), 2 deletions(-)
>>>
>>> Are there other changes you'd like me to make to this?  It would be
>>> really nice to get this in for 3.16 so the system doesn't just
>>> mysteriously hang when you use earlyprintk.
>>
>> We can probably take this as an -rc fix, so it should be fine.
>>
>> However I still don't see the point of exporting this clock and
>> polluting the global clkdev namespace. Even the diffstat looks better in v1.
> 
> OK, I'm happy to go back to v1 with the addition of the "return 0".
> 
> Mike: are you OK with that?
> 

One more question that just came to my mind: Why it is just the
aclk66_peri and not its children related to UARTs?

Exynos5420 clock driver still needs a little clean-up, so I'm okay with
any fix for now and changing this later if needed, but is this gate
clock for ACLK66_PERIC even needed? It seems to be marked with
CLK_IGNORE_UNUSED which suggests that it is not needed in this driver at
all, along with other similar clocks. AFAIK for power management
purposes our fine-grained approach is fine and we shouldn't need to use
the big gates.

Best regards,
Tomasz
Doug Anderson June 5, 2014, 8:10 p.m. UTC | #5
Tomasz,

On Thu, Jun 5, 2014 at 12:31 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> One more question that just came to my mind: Why it is just the
> aclk66_peri and not its children related to UARTs?

Can you re-read out the original patch description and see if it
answers that?  Basically: the UART was left on by the bootloader and
that's a requirement of earlyprintk but the common clock framework is
messing with aclk66_peric which is what's killing us.


> Exynos5420 clock driver still needs a little clean-up, so I'm okay with
> any fix for now and changing this later if needed, but is this gate
> clock for ACLK66_PERIC even needed? It seems to be marked with
> CLK_IGNORE_UNUSED which suggests that it is not needed in this driver at
> all, along with other similar clocks. AFAIK for power management
> purposes our fine-grained approach is fine and we shouldn't need to use
> the big gates.

Right, another option is to remove this gate from the clock tree (and
reparent all children on the gate's parent) and that would also fix
us.  The main advantages of the "big gate" as I see it:

1. There's a reasonable chance that our clock tree description is not
complete.  Patches to add previously undocumented clocks seems to be a
relatively common occurrence.  If one of those undocumented clocks
happens to be a child of aclk66_peric then we'll no longer be gating
it.

2. There might be a small amount of power saved by gating the clock
higher in the tree.

3. Having a more complete description of the clock tree is nice in
case someone outside the kernel does something.  If a stray pointer
(or a nonstandard bootloader) gates the clock then our tree won't show
problems, but the clock will still be gated.


Of course as soon as the first child of aclk66_peric is activated then
points #1 and #2 are invalid.  ...and #3 is a bit bogus because there
are A LOT of gates that we already don't model.


Also: the CLK_IGNORE_UNUSED is a bit bogus here.  That's not really a
useful flag in the case that you've got children that are enabled and
disabled.  Once your first child is enabled and disabled you'll be
disabled!

---

Hmmm, I think I've convinced myself that your suggestion of just
removing this gate from the table is the right thing to do.  Patch
will be coming up soon.

-Doug
Doug Anderson June 5, 2014, 8:42 p.m. UTC | #6
Hi,

On Thu, Jun 5, 2014 at 1:10 PM, Doug Anderson <dianders@chromium.org> wrote:
> Hmmm, I think I've convinced myself that your suggestion of just
> removing this gate from the table is the right thing to do.  Patch
> will be coming up soon.

It's here <https://patchwork.kernel.org/patch/4308631/>

Ironically, that patch has a much worse diffstat and also changes
devicetree bindings (!).  ...but it does seem better.

-Doug
diff mbox

Patch

diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 9d7d7ee..70b607a 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -890,8 +890,8 @@  static struct samsung_gate_clock exynos5x_gate_clks[] __initdata = {
 			GATE_BUS_TOP, 9, CLK_IGNORE_UNUSED, 0),
 	GATE(0, "aclk66_psgen", "mout_user_aclk66_psgen",
 			GATE_BUS_TOP, 10, CLK_IGNORE_UNUSED, 0),
-	GATE(CLK_ACLK66_PERIC, "aclk66_peric", "mout_user_aclk66_peric",
-			GATE_BUS_TOP, 11, CLK_IGNORE_UNUSED, 0),
+	GATE_A(CLK_ACLK66_PERIC, "aclk66_peric", "mout_user_aclk66_peric",
+			GATE_BUS_TOP, 11, CLK_IGNORE_UNUSED, 0, "aclk66_peric"),
 	GATE(0, "aclk266_isp", "mout_user_aclk266_isp",
 			GATE_BUS_TOP, 13, 0, 0),
 	GATE(0, "aclk166", "mout_user_aclk166",
@@ -1172,11 +1172,22 @@  static struct of_device_id ext_clk_match[] __initdata = {
 	{ },
 };
 
+/* Keep these clocks on until late_initcall */
+struct boot_clock {
+	char *name;
+	struct clk *clk;
+};
+
+static struct boot_clock boot_clocks[] __initdata = {
+	{ .name = "aclk66_peric", },
+};
+
 /* register exynos5420 clocks */
 static void __init exynos5x_clk_init(struct device_node *np,
 		enum exynos5x_soc soc)
 {
 	struct samsung_clk_provider *ctx;
+	int i;
 
 	if (np) {
 		reg_base = of_iomap(np, 0);
@@ -1226,6 +1237,11 @@  static void __init exynos5x_clk_init(struct device_node *np,
 	}
 
 	exynos5420_clk_sleep_init();
+
+	for (i = 0; i < ARRAY_SIZE(boot_clocks); i++) {
+		boot_clocks[i].clk = clk_get(NULL, boot_clocks[i].name);
+		clk_prepare_enable(boot_clocks[i].clk);
+	}
 }
 
 static void __init exynos5420_clk_init(struct device_node *np)
@@ -1239,3 +1255,16 @@  static void __init exynos5800_clk_init(struct device_node *np)
 	exynos5x_clk_init(np, EXYNOS5800);
 }
 CLK_OF_DECLARE(exynos5800_clk, "samsung,exynos5800-clock", exynos5800_clk_init);
+
+static int __init exynos5420_clk_late_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(boot_clocks); i++) {
+		clk_disable_unprepare(boot_clocks[i].clk);
+		clk_put(boot_clocks[i].clk);
+	}
+
+	return 0;
+}
+late_initcall(exynos5420_clk_late_init);