aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJerome Brunet <jbrunet@baylibre.com>2017-12-01 16:51:56 -0500
committerMichael Turquette <mturquette@baylibre.com>2017-12-19 19:17:49 -0500
commite55a839a7a1c561b7d2fbd9cc50b7d40dd2b3361 (patch)
tree44beaa04e9e9b6972241f9013f5824579a54a88e
parentca5e089a32c5ffba6c5101fdabdd6dea18041c34 (diff)
clk: add clock protection mechanism to clk core
The patch adds clk_core_protect and clk_core_unprotect to the internal CCF API. These functions allow to set a new constraint along the clock tree to prevent any change, even indirect, which may result in rate change or glitch. Tested-by: Maxime Ripard <maxime.ripard@free-electrons.com> Acked-by: Michael Turquette <mturquette@baylibre.com> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> Signed-off-by: Michael Turquette <mturquette@baylibre.com> Link: lkml.kernel.org/r/20171201215200.23523-7-jbrunet@baylibre.com
-rw-r--r--drivers/clk/clk.c119
-rw-r--r--include/linux/clk-provider.h1
2 files changed, 113 insertions, 7 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index bbe90babdae4..f69a2176cde1 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -62,6 +62,7 @@ struct clk_core {
62 bool orphan; 62 bool orphan;
63 unsigned int enable_count; 63 unsigned int enable_count;
64 unsigned int prepare_count; 64 unsigned int prepare_count;
65 unsigned int protect_count;
65 unsigned long min_rate; 66 unsigned long min_rate;
66 unsigned long max_rate; 67 unsigned long max_rate;
67 unsigned long accuracy; 68 unsigned long accuracy;
@@ -170,6 +171,11 @@ static void clk_enable_unlock(unsigned long flags)
170 spin_unlock_irqrestore(&enable_lock, flags); 171 spin_unlock_irqrestore(&enable_lock, flags);
171} 172}
172 173
174static bool clk_core_rate_is_protected(struct clk_core *core)
175{
176 return core->protect_count;
177}
178
173static bool clk_core_is_prepared(struct clk_core *core) 179static bool clk_core_is_prepared(struct clk_core *core)
174{ 180{
175 bool ret = false; 181 bool ret = false;
@@ -381,6 +387,11 @@ bool clk_hw_is_prepared(const struct clk_hw *hw)
381 return clk_core_is_prepared(hw->core); 387 return clk_core_is_prepared(hw->core);
382} 388}
383 389
390bool clk_hw_rate_is_protected(const struct clk_hw *hw)
391{
392 return clk_core_rate_is_protected(hw->core);
393}
394
384bool clk_hw_is_enabled(const struct clk_hw *hw) 395bool clk_hw_is_enabled(const struct clk_hw *hw)
385{ 396{
386 return clk_core_is_enabled(hw->core); 397 return clk_core_is_enabled(hw->core);
@@ -519,6 +530,68 @@ EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
519 530
520/*** clk api ***/ 531/*** clk api ***/
521 532
533static void clk_core_rate_unprotect(struct clk_core *core)
534{
535 lockdep_assert_held(&prepare_lock);
536
537 if (!core)
538 return;
539
540 if (WARN_ON(core->protect_count == 0))
541 return;
542
543 if (--core->protect_count > 0)
544 return;
545
546 clk_core_rate_unprotect(core->parent);
547}
548
549static int clk_core_rate_nuke_protect(struct clk_core *core)
550{
551 int ret;
552
553 lockdep_assert_held(&prepare_lock);
554
555 if (!core)
556 return -EINVAL;
557
558 if (core->protect_count == 0)
559 return 0;
560
561 ret = core->protect_count;
562 core->protect_count = 1;
563 clk_core_rate_unprotect(core);
564
565 return ret;
566}
567
568static void clk_core_rate_protect(struct clk_core *core)
569{
570 lockdep_assert_held(&prepare_lock);
571
572 if (!core)
573 return;
574
575 if (core->protect_count == 0)
576 clk_core_rate_protect(core->parent);
577
578 core->protect_count++;
579}
580
581static void clk_core_rate_restore_protect(struct clk_core *core, int count)
582{
583 lockdep_assert_held(&prepare_lock);
584
585 if (!core)
586 return;
587
588 if (count == 0)
589 return;
590
591 clk_core_rate_protect(core);
592 core->protect_count = count;
593}
594
522static void clk_core_unprepare(struct clk_core *core) 595static void clk_core_unprepare(struct clk_core *core)
523{ 596{
524 lockdep_assert_held(&prepare_lock); 597 lockdep_assert_held(&prepare_lock);
@@ -915,7 +988,9 @@ static int clk_core_determine_round_nolock(struct clk_core *core,
915 if (!core) 988 if (!core)
916 return 0; 989 return 0;
917 990
918 if (core->ops->determine_rate) { 991 if (clk_core_rate_is_protected(core)) {
992 req->rate = core->rate;
993 } else if (core->ops->determine_rate) {
919 return core->ops->determine_rate(core->hw, req); 994 return core->ops->determine_rate(core->hw, req);
920 } else if (core->ops->round_rate) { 995 } else if (core->ops->round_rate) {
921 rate = core->ops->round_rate(core->hw, req->rate, 996 rate = core->ops->round_rate(core->hw, req->rate,
@@ -1661,7 +1736,7 @@ static void clk_change_rate(struct clk_core *core)
1661static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core, 1736static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
1662 unsigned long req_rate) 1737 unsigned long req_rate)
1663{ 1738{
1664 int ret; 1739 int ret, cnt;
1665 struct clk_rate_request req; 1740 struct clk_rate_request req;
1666 1741
1667 lockdep_assert_held(&prepare_lock); 1742 lockdep_assert_held(&prepare_lock);
@@ -1669,11 +1744,19 @@ static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
1669 if (!core) 1744 if (!core)
1670 return 0; 1745 return 0;
1671 1746
1747 /* simulate what the rate would be if it could be freely set */
1748 cnt = clk_core_rate_nuke_protect(core);
1749 if (cnt < 0)
1750 return cnt;
1751
1672 clk_core_get_boundaries(core, &req.min_rate, &req.max_rate); 1752 clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
1673 req.rate = req_rate; 1753 req.rate = req_rate;
1674 1754
1675 ret = clk_core_round_rate_nolock(core, &req); 1755 ret = clk_core_round_rate_nolock(core, &req);
1676 1756
1757 /* restore the protection */
1758 clk_core_rate_restore_protect(core, cnt);
1759
1677 return ret ? 0 : req.rate; 1760 return ret ? 0 : req.rate;
1678} 1761}
1679 1762
@@ -1693,6 +1776,10 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
1693 if (rate == clk_core_get_rate_nolock(core)) 1776 if (rate == clk_core_get_rate_nolock(core))
1694 return 0; 1777 return 0;
1695 1778
1779 /* fail on a direct rate set of a protected provider */
1780 if (clk_core_rate_is_protected(core))
1781 return -EBUSY;
1782
1696 if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) 1783 if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
1697 return -EBUSY; 1784 return -EBUSY;
1698 1785
@@ -1937,6 +2024,9 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
1937 if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) 2024 if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count)
1938 return -EBUSY; 2025 return -EBUSY;
1939 2026
2027 if (clk_core_rate_is_protected(core))
2028 return -EBUSY;
2029
1940 /* try finding the new parent index */ 2030 /* try finding the new parent index */
1941 if (parent) { 2031 if (parent) {
1942 p_index = clk_fetch_parent_index(core, parent); 2032 p_index = clk_fetch_parent_index(core, parent);
@@ -2018,6 +2108,9 @@ static int clk_core_set_phase_nolock(struct clk_core *core, int degrees)
2018 if (!core) 2108 if (!core)
2019 return 0; 2109 return 0;
2020 2110
2111 if (clk_core_rate_is_protected(core))
2112 return -EBUSY;
2113
2021 trace_clk_set_phase(core, degrees); 2114 trace_clk_set_phase(core, degrees);
2022 2115
2023 if (core->ops->set_phase) 2116 if (core->ops->set_phase)
@@ -2148,11 +2241,12 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
2148 if (!c) 2241 if (!c)
2149 return; 2242 return;
2150 2243
2151 seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n", 2244 seq_printf(s, "%*s%-*s %11d %12d %12d %11lu %10lu %-3d\n",
2152 level * 3 + 1, "", 2245 level * 3 + 1, "",
2153 30 - level * 3, c->name, 2246 30 - level * 3, c->name,
2154 c->enable_count, c->prepare_count, clk_core_get_rate(c), 2247 c->enable_count, c->prepare_count, c->protect_count,
2155 clk_core_get_accuracy(c), clk_core_get_phase(c)); 2248 clk_core_get_rate(c), clk_core_get_accuracy(c),
2249 clk_core_get_phase(c));
2156} 2250}
2157 2251
2158static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, 2252static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
@@ -2174,8 +2268,8 @@ static int clk_summary_show(struct seq_file *s, void *data)
2174 struct clk_core *c; 2268 struct clk_core *c;
2175 struct hlist_head **lists = (struct hlist_head **)s->private; 2269 struct hlist_head **lists = (struct hlist_head **)s->private;
2176 2270
2177 seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n"); 2271 seq_puts(s, " clock enable_cnt prepare_cnt protect_cnt rate accuracy phase\n");
2178 seq_puts(s, "----------------------------------------------------------------------------------------\n"); 2272 seq_puts(s, "----------------------------------------------------------------------------------------------------\n");
2179 2273
2180 clk_prepare_lock(); 2274 clk_prepare_lock();
2181 2275
@@ -2210,6 +2304,7 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
2210 seq_printf(s, "\"%s\": { ", c->name); 2304 seq_printf(s, "\"%s\": { ", c->name);
2211 seq_printf(s, "\"enable_count\": %d,", c->enable_count); 2305 seq_printf(s, "\"enable_count\": %d,", c->enable_count);
2212 seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); 2306 seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
2307 seq_printf(s, "\"protect_count\": %d,", c->protect_count);
2213 seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); 2308 seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
2214 seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); 2309 seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
2215 seq_printf(s, "\"phase\": %d", clk_core_get_phase(c)); 2310 seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
@@ -2340,6 +2435,11 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
2340 if (!d) 2435 if (!d)
2341 goto err_out; 2436 goto err_out;
2342 2437
2438 d = debugfs_create_u32("clk_protect_count", S_IRUGO, core->dentry,
2439 (u32 *)&core->protect_count);
2440 if (!d)
2441 goto err_out;
2442
2343 d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry, 2443 d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry,
2344 (u32 *)&core->notifier_count); 2444 (u32 *)&core->notifier_count);
2345 if (!d) 2445 if (!d)
@@ -2911,6 +3011,11 @@ void clk_unregister(struct clk *clk)
2911 if (clk->core->prepare_count) 3011 if (clk->core->prepare_count)
2912 pr_warn("%s: unregistering prepared clock: %s\n", 3012 pr_warn("%s: unregistering prepared clock: %s\n",
2913 __func__, clk->core->name); 3013 __func__, clk->core->name);
3014
3015 if (clk->core->protect_count)
3016 pr_warn("%s: unregistering protected clock: %s\n",
3017 __func__, clk->core->name);
3018
2914 kref_put(&clk->core->ref, __clk_release); 3019 kref_put(&clk->core->ref, __clk_release);
2915unlock: 3020unlock:
2916 clk_prepare_unlock(); 3021 clk_prepare_unlock();
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 7c925e6211f1..73ac87f34df9 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -744,6 +744,7 @@ unsigned long clk_hw_get_rate(const struct clk_hw *hw);
744unsigned long __clk_get_flags(struct clk *clk); 744unsigned long __clk_get_flags(struct clk *clk);
745unsigned long clk_hw_get_flags(const struct clk_hw *hw); 745unsigned long clk_hw_get_flags(const struct clk_hw *hw);
746bool clk_hw_is_prepared(const struct clk_hw *hw); 746bool clk_hw_is_prepared(const struct clk_hw *hw);
747bool clk_hw_rate_is_protected(const struct clk_hw *hw);
747bool clk_hw_is_enabled(const struct clk_hw *hw); 748bool clk_hw_is_enabled(const struct clk_hw *hw);
748bool __clk_is_enabled(struct clk *clk); 749bool __clk_is_enabled(struct clk *clk);
749struct clk *__clk_lookup(const char *name); 750struct clk *__clk_lookup(const char *name);