clk: Add tracepoints for hardware operations
authorStephen Boyd <sboyd@codeaurora.org>
Mon, 2 Feb 2015 22:37:41 +0000 (14:37 -0800)
committerStephen Boyd <sboyd@codeaurora.org>
Thu, 12 Mar 2015 19:18:51 +0000 (12:18 -0700)
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>
Signed-off-by: Michael Turquette <mturquette@linaro.org>
drivers/clk/clk.c
include/trace/events/clk.h [new file with mode: 0644]

index 0b3f39c037857ba9803d029bfdbde7ec1a0f2e84..42064cec236409b1e4af817d2d6de22287438a89 100644 (file)
@@ -77,6 +77,9 @@ struct clk_core {
        struct kref             ref;
 };
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/clk.h>
+
 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 (file)
index 0000000..7586072
--- /dev/null
@@ -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>