diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0b3f39c03785..42064cec2364 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -77,6 +77,9 @@ struct clk_core { struct kref ref; }; +#define CREATE_TRACE_POINTS +#include + struct clk { struct clk_core *core; const char *dev_id; @@ -492,10 +495,12 @@ static void clk_unprepare_unused_subtree(struct clk_core *clk) return; if (clk_core_is_prepared(clk)) { + trace_clk_unprepare(clk); if (clk->ops->unprepare_unused) clk->ops->unprepare_unused(clk->hw); else if (clk->ops->unprepare) clk->ops->unprepare(clk->hw); + trace_clk_unprepare_complete(clk); } } @@ -524,10 +529,12 @@ static void clk_disable_unused_subtree(struct clk_core *clk) * back to .disable */ if (clk_core_is_enabled(clk)) { + trace_clk_disable(clk); if (clk->ops->disable_unused) clk->ops->disable_unused(clk->hw); else if (clk->ops->disable) clk->ops->disable(clk->hw); + trace_clk_disable_complete(clk); } unlock_out: @@ -907,9 +914,12 @@ static void clk_core_unprepare(struct clk_core *clk) WARN_ON(clk->enable_count > 0); + trace_clk_unprepare(clk); + if (clk->ops->unprepare) clk->ops->unprepare(clk->hw); + trace_clk_unprepare_complete(clk); clk_core_unprepare(clk->parent); } @@ -947,12 +957,16 @@ static int clk_core_prepare(struct clk_core *clk) if (ret) return ret; - if (clk->ops->prepare) { + trace_clk_prepare(clk); + + if (clk->ops->prepare) ret = clk->ops->prepare(clk->hw); - if (ret) { - clk_core_unprepare(clk->parent); - return ret; - } + + trace_clk_prepare_complete(clk); + + if (ret) { + clk_core_unprepare(clk->parent); + return ret; } } @@ -999,9 +1013,13 @@ static void clk_core_disable(struct clk_core *clk) if (--clk->enable_count > 0) return; + trace_clk_disable(clk); + if (clk->ops->disable) clk->ops->disable(clk->hw); + trace_clk_disable_complete(clk); + clk_core_disable(clk->parent); } @@ -1054,12 +1072,16 @@ static int clk_core_enable(struct clk_core *clk) if (ret) return ret; - if (clk->ops->enable) { + trace_clk_enable(clk); + + if (clk->ops->enable) ret = clk->ops->enable(clk->hw); - if (ret) { - clk_core_disable(clk->parent); - return ret; - } + + trace_clk_enable_complete(clk); + + if (ret) { + clk_core_disable(clk->parent); + return ret; } } @@ -1490,10 +1512,14 @@ static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent, old_parent = __clk_set_parent_before(clk, parent); + trace_clk_set_parent(clk, parent); + /* change clock input source */ if (parent && clk->ops->set_parent) ret = clk->ops->set_parent(clk->hw, p_index); + trace_clk_set_parent_complete(clk, parent); + if (ret) { flags = clk_enable_lock(); clk_reparent(clk, old_parent); @@ -1719,6 +1745,7 @@ static void clk_change_rate(struct clk_core *clk) if (clk->new_parent && clk->new_parent != clk->parent) { old_parent = __clk_set_parent_before(clk, clk->new_parent); + trace_clk_set_parent(clk, clk->new_parent); if (clk->ops->set_rate_and_parent) { skip_set_rate = true; @@ -1729,12 +1756,17 @@ static void clk_change_rate(struct clk_core *clk) clk->ops->set_parent(clk->hw, clk->new_parent_index); } + trace_clk_set_parent_complete(clk, clk->new_parent); __clk_set_parent_after(clk, clk->new_parent, old_parent); } + trace_clk_set_rate(clk, clk->new_rate); + if (!skip_set_rate && clk->ops->set_rate) clk->ops->set_rate(clk->hw, clk->new_rate, best_parent_rate); + trace_clk_set_rate_complete(clk, clk->new_rate); + clk->rate = clk_recalc(clk, best_parent_rate); if (clk->notifier_count && old_rate != clk->rate) @@ -2135,9 +2167,13 @@ int clk_set_phase(struct clk *clk, int degrees) clk_prepare_lock(); + trace_clk_set_phase(clk->core, degrees); + if (clk->core->ops->set_phase) ret = clk->core->ops->set_phase(clk->core->hw, degrees); + trace_clk_set_phase_complete(clk->core, degrees); + if (!ret) clk->core->phase = degrees; diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h new file mode 100644 index 000000000000..758607226bfd --- /dev/null +++ b/include/trace/events/clk.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM clk + +#if !defined(_TRACE_CLK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_CLK_H + +#include + +struct clk_core; + +DECLARE_EVENT_CLASS(clk, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core), + + TP_STRUCT__entry( + __string( name, core->name ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + ), + + TP_printk("%s", __get_str(name)) +); + +DEFINE_EVENT(clk, clk_enable, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_enable_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_disable, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_disable_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_prepare, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_prepare_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_unprepare, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DEFINE_EVENT(clk, clk_unprepare_complete, + + TP_PROTO(struct clk_core *core), + + TP_ARGS(core) +); + +DECLARE_EVENT_CLASS(clk_rate, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate), + + TP_STRUCT__entry( + __string( name, core->name ) + __field(unsigned long, rate ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __entry->rate = rate; + ), + + TP_printk("%s %lu", __get_str(name), (unsigned long)__entry->rate) +); + +DEFINE_EVENT(clk_rate, clk_set_rate, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate) +); + +DEFINE_EVENT(clk_rate, clk_set_rate_complete, + + TP_PROTO(struct clk_core *core, unsigned long rate), + + TP_ARGS(core, rate) +); + +DECLARE_EVENT_CLASS(clk_parent, + + TP_PROTO(struct clk_core *core, struct clk_core *parent), + + TP_ARGS(core, parent), + + TP_STRUCT__entry( + __string( name, core->name ) + __string( pname, parent->name ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __assign_str(pname, parent->name); + ), + + TP_printk("%s %s", __get_str(name), __get_str(pname)) +); + +DEFINE_EVENT(clk_parent, clk_set_parent, + + TP_PROTO(struct clk_core *core, struct clk_core *parent), + + TP_ARGS(core, parent) +); + +DEFINE_EVENT(clk_parent, clk_set_parent_complete, + + TP_PROTO(struct clk_core *core, struct clk_core *parent), + + TP_ARGS(core, parent) +); + +DECLARE_EVENT_CLASS(clk_phase, + + TP_PROTO(struct clk_core *core, int phase), + + TP_ARGS(core, phase), + + TP_STRUCT__entry( + __string( name, core->name ) + __field( int, phase ) + ), + + TP_fast_assign( + __assign_str(name, core->name); + __entry->phase = phase; + ), + + TP_printk("%s %d", __get_str(name), (int)__entry->phase) +); + +DEFINE_EVENT(clk_phase, clk_set_phase, + + TP_PROTO(struct clk_core *core, int phase), + + TP_ARGS(core, phase) +); + +DEFINE_EVENT(clk_phase, clk_set_phase_complete, + + TP_PROTO(struct clk_core *core, int phase), + + TP_ARGS(core, phase) +); + +#endif /* _TRACE_CLK_H */ + +/* This part must be outside protection */ +#include