diff options
author | Jerome Brunet <jbrunet@baylibre.com> | 2017-12-01 16:51:56 -0500 |
---|---|---|
committer | Michael Turquette <mturquette@baylibre.com> | 2017-12-19 19:17:49 -0500 |
commit | e55a839a7a1c561b7d2fbd9cc50b7d40dd2b3361 (patch) | |
tree | 44beaa04e9e9b6972241f9013f5824579a54a88e | |
parent | ca5e089a32c5ffba6c5101fdabdd6dea18041c34 (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.c | 119 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 1 |
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 | ||
174 | static bool clk_core_rate_is_protected(struct clk_core *core) | ||
175 | { | ||
176 | return core->protect_count; | ||
177 | } | ||
178 | |||
173 | static bool clk_core_is_prepared(struct clk_core *core) | 179 | static 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 | ||
390 | bool clk_hw_rate_is_protected(const struct clk_hw *hw) | ||
391 | { | ||
392 | return clk_core_rate_is_protected(hw->core); | ||
393 | } | ||
394 | |||
384 | bool clk_hw_is_enabled(const struct clk_hw *hw) | 395 | bool 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 | ||
533 | static 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 | |||
549 | static 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 | |||
568 | static 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 | |||
581 | static 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 | |||
522 | static void clk_core_unprepare(struct clk_core *core) | 595 | static 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) | |||
1661 | static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core, | 1736 | static 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 | ||
2158 | static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, | 2252 | static 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); |
2915 | unlock: | 3020 | unlock: |
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); | |||
744 | unsigned long __clk_get_flags(struct clk *clk); | 744 | unsigned long __clk_get_flags(struct clk *clk); |
745 | unsigned long clk_hw_get_flags(const struct clk_hw *hw); | 745 | unsigned long clk_hw_get_flags(const struct clk_hw *hw); |
746 | bool clk_hw_is_prepared(const struct clk_hw *hw); | 746 | bool clk_hw_is_prepared(const struct clk_hw *hw); |
747 | bool clk_hw_rate_is_protected(const struct clk_hw *hw); | ||
747 | bool clk_hw_is_enabled(const struct clk_hw *hw); | 748 | bool clk_hw_is_enabled(const struct clk_hw *hw); |
748 | bool __clk_is_enabled(struct clk *clk); | 749 | bool __clk_is_enabled(struct clk *clk); |
749 | struct clk *__clk_lookup(const char *name); | 750 | struct clk *__clk_lookup(const char *name); |