[RFC 11/14] SoundWire: Add tracing for Slave register read/write

From: Hardik Shah
Date: Fri Oct 21 2016 - 08:40:40 EST


Signed-off-by: Hardik Shah <hardik.t.shah@xxxxxxxxx>
Signed-off-by: Sanyog Kale <sanyog.r.kale@xxxxxxxxx>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@xxxxxxxxxxxxxxx>
---
include/sound/sdw_bus.h | 7 ++
include/trace/events/sdw.h | 209 ++++++++++++++++++++++++++++++++++++++++++++
sound/sdw/sdw.c | 37 ++++++++
3 files changed, 253 insertions(+)
create mode 100644 include/trace/events/sdw.h

diff --git a/include/sound/sdw_bus.h b/include/sound/sdw_bus.h
index 3ea0c71..ad3586e 100644
--- a/include/sound/sdw_bus.h
+++ b/include/sound/sdw_bus.h
@@ -894,5 +894,12 @@ int snd_sdw_config_ports(struct sdw_master *mstr, struct sdw_slave *slave,
*/
int snd_sdw_slave_transfer(struct sdw_master *master, struct sdw_msg *msg,
unsigned int num);
+
+/* Function to enable tracing */
+void sdw_transfer_trace_reg(void);
+
+/* Function to disable tracing */
+void sdw_transfer_trace_unreg(void);
+
#endif /* _LINUX_SDW_BUS_H */

diff --git a/include/trace/events/sdw.h b/include/trace/events/sdw.h
new file mode 100644
index 0000000..447b86e
--- /dev/null
+++ b/include/trace/events/sdw.h
@@ -0,0 +1,209 @@
+/*
+ * sdw.h - SDW message transfer tracepoints.
+ *
+ * Author: Hardik Shah <hardik.t.shah@xxxxxxxxx>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM sdw
+
+#if !defined(_TRACE_SDW_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SDW_H
+
+#include <linux/mod_devicetable.h>
+#include <sound/sdw_bus.h>
+#include <linux/tracepoint.h>
+
+/*
+ * __sdw_transfer() write request
+ */
+TRACE_EVENT_FN(sdw_write,
+ TP_PROTO(const struct sdw_master *mstr,
+ const struct sdw_msg *msg,
+ int num),
+ TP_ARGS(mstr, msg, num),
+ TP_STRUCT__entry(
+ __field(int, master_nr)
+ __field(__u16, msg_nr)
+ __field(__u8, addr_page1)
+ __field(__u8, addr_page2)
+ __field(__u16, addr)
+ __field(__u16, flag)
+ __field(__u16, len)
+ __dynamic_array(__u8, buf, msg->len)),
+ TP_fast_assign(
+ __entry->master_nr = mstr->nr;
+ __entry->msg_nr = num;
+ __entry->addr = msg->addr;
+ __entry->flag = msg->r_w_flag;
+ __entry->len = msg->len;
+ __entry->addr_page1 = msg->addr_page1;
+ __entry->addr_page2 = msg->addr_page2;
+ memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
+ ),
+ TP_printk("sdw-%d #%u a=%03x addr_page1=%04x addr_page2=%04x f=%04x l=%u [%*phD]",
+ __entry->master_nr,
+ __entry->msg_nr,
+ __entry->addr,
+ __entry->addr_page1,
+ __entry->addr_page2,
+ __entry->flag,
+ __entry->len,
+ __entry->len, __get_dynamic_array(buf)
+ ),
+ sdw_transfer_trace_reg,
+ sdw_transfer_trace_unreg);
+
+/*
+ * __sdw_transfer() read request
+ */
+TRACE_EVENT_FN(sdw_read,
+ TP_PROTO(const struct sdw_master *mstr, const struct sdw_msg *msg,
+ int num),
+ TP_ARGS(mstr, msg, num),
+ TP_STRUCT__entry(
+ __field(int, master_nr)
+ __field(__u16, msg_nr)
+ __field(__u8, addr_page1)
+ __field(__u8, addr_page2)
+ __field(__u16, addr)
+ __field(__u16, flag)
+ __field(__u16, len)
+ __dynamic_array(__u8, buf, msg->len)),
+ TP_fast_assign(
+ __entry->master_nr = mstr->nr;
+ __entry->msg_nr = num;
+ __entry->addr = msg->addr;
+ __entry->flag = msg->r_w_flag;
+ __entry->len = msg->len;
+ __entry->addr_page1 = msg->addr_page1;
+ __entry->addr_page2 = msg->addr_page2;
+ memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
+ ),
+ TP_printk("sdw-%d #%u a=%03x addr_page1=%04x addr_page2=%04x f=%04x l=%u [%*phD]",
+ __entry->master_nr,
+ __entry->msg_nr,
+ __entry->addr,
+ __entry->addr_page1,
+ __entry->addr_page2,
+ __entry->flag,
+ __entry->len,
+ __entry->len, __get_dynamic_array(buf)
+ ),
+ sdw_transfer_trace_reg,
+ sdw_transfer_trace_unreg);
+
+/*
+ * __sdw_transfer() read reply
+ */
+TRACE_EVENT_FN(sdw_reply,
+ TP_PROTO(const struct sdw_master *mstr,
+ const struct sdw_msg *msg,
+ int num),
+ TP_ARGS(mstr, msg, num),
+ TP_STRUCT__entry(
+ __field(int, master_nr)
+ __field(__u16, msg_nr)
+ __field(__u16, addr)
+ __field(__u16, flag)
+ __field(__u16, len)
+ __dynamic_array(__u8, buf, msg->len)),
+ TP_fast_assign(
+ __entry->master_nr = mstr->nr;
+ __entry->msg_nr = num;
+ __entry->addr = msg->addr;
+ __entry->flag = msg->r_w_flag;
+ __entry->len = msg->len;
+ memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
+ ),
+ TP_printk("sdw-%d #%u a=%03x f=%04x l=%u [%*phD]",
+ __entry->master_nr,
+ __entry->msg_nr,
+ __entry->addr,
+ __entry->flag,
+ __entry->len,
+ __entry->len, __get_dynamic_array(buf)
+ ),
+ sdw_transfer_trace_reg,
+ sdw_transfer_trace_unreg);
+
+/*
+ * __sdw_transfer() result
+ */
+TRACE_EVENT_FN(sdw_result,
+ TP_PROTO(const struct sdw_master *mstr, int num, int ret),
+ TP_ARGS(mstr, num, ret),
+ TP_STRUCT__entry(
+ __field(int, master_nr)
+ __field(__u16, nr_msgs)
+ __field(__s16, ret)
+ ),
+ TP_fast_assign(
+ __entry->master_nr = mstr->nr;
+ __entry->nr_msgs = num;
+ __entry->ret = ret;
+ ),
+ TP_printk("sdw-%d n=%u ret=%d",
+ __entry->master_nr,
+ __entry->nr_msgs,
+ __entry->ret
+ ),
+ sdw_transfer_trace_reg,
+ sdw_transfer_trace_unreg);
+
+#endif /* _TRACE_SDW_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/sound/sdw/sdw.c b/sound/sdw/sdw.c
index 449060e..71d2550 100644
--- a/sound/sdw/sdw.c
+++ b/sound/sdw/sdw.c
@@ -70,6 +70,8 @@

#include "sdw_priv.h"

+#define CREATE_TRACE_POINTS
+#include <trace/events/sdw.h>
/*
* Global SoundWire core instance contains list of Masters registered, core
* lock and SoundWire stream tags.
@@ -335,6 +337,17 @@ static int sdw_match(struct device *dev, struct device_driver *driver)
.match = sdw_match,
.pm = &soundwire_pm,
};
+static struct static_key sdw_trace_msg = STATIC_KEY_INIT_FALSE;
+
+void sdw_transfer_trace_reg(void)
+{
+ static_key_slow_inc(&sdw_trace_msg);
+}
+
+void sdw_transfer_trace_unreg(void)
+{
+ static_key_slow_dec(&sdw_trace_msg);
+}

static int sdw_find_free_dev_num(struct sdw_master *mstr,
struct sdw_msg *msg)
@@ -601,6 +614,21 @@ static int sdw_transfer(struct sdw_master *mstr, struct sdw_msg *msg, int num,
u8 prev_adr_pg1 = 0;
u8 prev_adr_pg2 = 0;

+ /*
+ * sdw_trace_msg gets enabled when trace point sdw_slave_transfer gets
+ * enabled. This is an efficient way of keeping the for-loop from
+ * being executed when not needed.
+ */
+ if (static_key_false(&sdw_trace_msg)) {
+ int j;
+
+ for (j = 0; j < num; j++)
+ if (msg[j].r_w_flag & SDW_MSG_FLAG_READ)
+ trace_sdw_read(mstr, &msg[j], j);
+ else
+ trace_sdw_write(mstr, &msg[j], j);
+ }
+
for (i = 0; i < num; i++) {

/* Reset timeout for every message */
@@ -665,6 +693,15 @@ static int sdw_transfer(struct sdw_master *mstr, struct sdw_msg *msg, int num,
}
}

+ if (static_key_false(&sdw_trace_msg)) {
+ int j;
+
+ for (j = 0; j < msg->len; j++)
+ if (msg[j].r_w_flag & SDW_MSG_FLAG_READ)
+ trace_sdw_reply(mstr, &msg[j], j);
+ trace_sdw_result(mstr, j, ret);
+ }
+
if (!ret)
return i + 1;

--
1.7.9.5