Messages in this thread Patch in this message | | | From | Stephen Boyd <> | Subject | [PATCH] clk: Add tracepoints for hardware operations | Date | Fri, 30 Jan 2015 16:16:11 -0800 |
| |
It's useful to have tracepoints around operations that change the hardware state so that we can debug clock hardware performance and operations. Four basic types of events are supported: on/off events for enable, disable, prepare, unprepare that only record an event and a clock name, rate changing events for clk_set_{min_,max_}rate{_range}(), phase changing events for clk_set_phase() and parent changing events for clk_set_parent().
Cc: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> --- drivers/clk/clk.c | 32 ++++++++ include/trace/events/clk.h | 198 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 include/trace/events/clk.h
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a29daf9edea4..271c3fe71277 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -22,6 +22,9 @@ #include <linux/init.h> #include <linux/sched.h> +#define CREATE_TRACE_POINTS +#include <trace/events/clk.h> + #include "clk.h" static DEFINE_SPINLOCK(enable_lock); @@ -448,10 +451,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); } } @@ -478,10 +483,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: @@ -861,9 +868,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); } @@ -901,6 +911,8 @@ static int clk_core_prepare(struct clk_core *clk) if (ret) return ret; + trace_clk_prepare(clk); + if (clk->ops->prepare) { ret = clk->ops->prepare(clk->hw); if (ret) { @@ -908,6 +920,8 @@ static int clk_core_prepare(struct clk_core *clk) return ret; } } + + trace_clk_prepare_complete(clk); } clk->prepare_count++; @@ -953,9 +967,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); } @@ -1008,6 +1026,7 @@ static int clk_core_enable(struct clk_core *clk) if (ret) return ret; + trace_clk_enable(clk); if (clk->ops->enable) { ret = clk->ops->enable(clk->hw); if (ret) { @@ -1015,6 +1034,7 @@ static int clk_core_enable(struct clk_core *clk) return ret; } } + trace_clk_enable_complete(clk); } clk->enable_count++; @@ -1383,6 +1403,8 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *clk, unsigned long flags; struct clk_core *old_parent = clk->parent; + trace_clk_set_parent(clk, parent); + /* * Migrate prepare state between parents and prevent race with * clk_enable(). @@ -1427,6 +1449,8 @@ static void __clk_set_parent_after(struct clk_core *core, clk_core_disable(old_parent); clk_core_unprepare(old_parent); } + + trace_clk_set_parent_complete(core, parent); } static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent, @@ -1663,6 +1687,8 @@ static void clk_change_rate(struct clk_core *clk) else if (clk->parent) best_parent_rate = clk->parent->rate; + trace_clk_set_rate(clk, clk->new_rate); + if (clk->new_parent && clk->new_parent != clk->parent) { old_parent = __clk_set_parent_before(clk, clk->new_parent); @@ -1681,6 +1707,8 @@ static void clk_change_rate(struct clk_core *clk) 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) @@ -2081,6 +2109,8 @@ 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) goto out_unlock; @@ -2090,6 +2120,8 @@ int clk_set_phase(struct clk *clk, int degrees) clk->core->phase = degrees; out_unlock: + trace_clk_set_phase_complete(clk->core, degrees); + clk_prepare_unlock(); out: 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 <linux/tracepoint.h> + +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 <trace/define_trace.h> -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
| |