Commit dca1a4b5ff6e2c25adeff366eb06270dadeab3db

Authored by Boris Brezillon
Committed by Michael Turquette
1 parent 98f87a7ba2

clk: at91: keep slow clk enabled to prevent system hang

All slow clk users are not properly claiming it (get + prepare + enable)
before using it.
If all users properly claiming this clock release it, the clock is
disabled, but faulty users still depends on it, and the system hangs.

This fix prevents the slow clock from being disabled, and should solve the
hanging issue, but offending drivers should be patched to properly claim
this clock.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reported-by: Bo Shen <voice.shen@atmel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Michael Turquette <mturquette@linaro.org>

Showing 1 changed file with 27 additions and 0 deletions Side-by-side Diff

drivers/clk/at91/clk-slow.c
... ... @@ -70,6 +70,7 @@
70 70  
71 71 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
72 72  
  73 +static struct clk *slow_clk;
73 74  
74 75 static int clk_slow_osc_prepare(struct clk_hw *hw)
75 76 {
... ... @@ -357,6 +358,8 @@
357 358 clk = clk_register(NULL, &slowck->hw);
358 359 if (IS_ERR(clk))
359 360 kfree(slowck);
  361 + else
  362 + slow_clk = clk;
360 363  
361 364 return clk;
362 365 }
... ... @@ -433,6 +436,8 @@
433 436 clk = clk_register(NULL, &slowck->hw);
434 437 if (IS_ERR(clk))
435 438 kfree(slowck);
  439 + else
  440 + slow_clk = clk;
436 441  
437 442 return clk;
438 443 }
... ... @@ -465,4 +470,26 @@
465 470  
466 471 of_clk_add_provider(np, of_clk_src_simple_get, clk);
467 472 }
  473 +
  474 +/*
  475 + * FIXME: All slow clk users are not properly claiming it (get + prepare +
  476 + * enable) before using it.
  477 + * If all users properly claiming this clock decide that they don't need it
  478 + * anymore (or are removed), it is disabled while faulty users are still
  479 + * requiring it, and the system hangs.
  480 + * Prevent this clock from being disabled until all users are properly
  481 + * requesting it.
  482 + * Once this is done we should remove this function and the slow_clk variable.
  483 + */
  484 +static int __init of_at91_clk_slow_retain(void)
  485 +{
  486 + if (!slow_clk)
  487 + return 0;
  488 +
  489 + __clk_get(slow_clk);
  490 + clk_prepare_enable(slow_clk);
  491 +
  492 + return 0;
  493 +}
  494 +arch_initcall(of_at91_clk_slow_retain);