From d9a83d62b326574fb4831b64317a82a42642a9a2 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 6 Mar 2014 13:35:59 +0000 Subject: i2c: Add message transfer tracepoints for I2C Add tracepoints into the I2C message transfer function to retrieve the message sent or received. The following config options must be turned on to make use of the facility: CONFIG_FTRACE CONFIG_ENABLE_DEFAULT_TRACERS The I2C tracepoint can be enabled thusly: echo 1 >/sys/kernel/debug/tracing/events/i2c/enable and will dump messages that can be viewed in /sys/kernel/debug/tracing/trace that look like: ... i2c_write: i2c-5 #0 a=044 f=0000 l=2 [02-14] ... i2c_read: i2c-5 #1 a=044 f=0001 l=4 ... i2c_reply: i2c-5 #1 a=044 f=0001 l=4 [33-00-00-00] ... i2c_result: i2c-5 n=2 ret=2 formatted as: i2c- # a= f= l= n= ret= [] The operation is done between the i2c_write/i2c_read lines and the i2c_reply and i2c_result lines so that if the hardware hangs, the trace buffer can be consulted to determine the problematic operation. The adapters to be traced can be selected by something like: echo adapter_nr==1 >/sys/kernel/debug/tracing/events/i2c/filter These changes are based on code from Steven Rostedt. Signed-off-by: Steven Rostedt Signed-off-by: David Howells Reviewed-by: Steven Rostedt [wsa: adapted path for 'enable' in the commit msg] Signed-off-by: Wolfram Sang --- include/trace/events/i2c.h | 150 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 include/trace/events/i2c.h (limited to 'include/trace/events') diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h new file mode 100644 index 0000000..4800207 --- /dev/null +++ b/include/trace/events/i2c.h @@ -0,0 +1,150 @@ +/* I2C message transfer tracepoints + * + * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM i2c + +#if !defined(_TRACE_I2C_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_I2C_H + +#include +#include + +/* + * drivers/i2c/i2c-core.c + */ +extern void i2c_transfer_trace_reg(void); +extern void i2c_transfer_trace_unreg(void); + +/* + * __i2c_transfer() write request + */ +TRACE_EVENT_FN(i2c_write, + TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg, + int num), + TP_ARGS(adap, msg, num), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, msg_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u16, len ) + __dynamic_array(__u8, buf, msg->len) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->msg_nr = num; + __entry->addr = msg->addr; + __entry->flags = msg->flags; + __entry->len = msg->len; + memcpy(__get_dynamic_array(buf), msg->buf, msg->len); + ), + TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]", + __entry->adapter_nr, + __entry->msg_nr, + __entry->addr, + __entry->flags, + __entry->len, + __entry->len, __get_dynamic_array(buf) + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +/* + * __i2c_transfer() read request + */ +TRACE_EVENT_FN(i2c_read, + TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg, + int num), + TP_ARGS(adap, msg, num), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, msg_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u16, len ) + ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->msg_nr = num; + __entry->addr = msg->addr; + __entry->flags = msg->flags; + __entry->len = msg->len; + ), + TP_printk("i2c-%d #%u a=%03x f=%04x l=%u", + __entry->adapter_nr, + __entry->msg_nr, + __entry->addr, + __entry->flags, + __entry->len + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +/* + * __i2c_transfer() read reply + */ +TRACE_EVENT_FN(i2c_reply, + TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg, + int num), + TP_ARGS(adap, msg, num), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, msg_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u16, len ) + __dynamic_array(__u8, buf, msg->len) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->msg_nr = num; + __entry->addr = msg->addr; + __entry->flags = msg->flags; + __entry->len = msg->len; + memcpy(__get_dynamic_array(buf), msg->buf, msg->len); + ), + TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]", + __entry->adapter_nr, + __entry->msg_nr, + __entry->addr, + __entry->flags, + __entry->len, + __entry->len, __get_dynamic_array(buf) + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +/* + * __i2c_transfer() result + */ +TRACE_EVENT_FN(i2c_result, + TP_PROTO(const struct i2c_adapter *adap, int num, int ret), + TP_ARGS(adap, num, ret), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, nr_msgs ) + __field(__s16, ret ) + ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->nr_msgs = num; + __entry->ret = ret; + ), + TP_printk("i2c-%d n=%u ret=%d", + __entry->adapter_nr, + __entry->nr_msgs, + __entry->ret + ), + i2c_transfer_trace_reg, + i2c_transfer_trace_unreg); + +#endif /* _TRACE_I2C_H */ + +/* This part must be outside protection */ +#include -- cgit v1.1 From 8a325997d95d446206b204b7859e055a0315e4fa Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 6 Mar 2014 13:36:06 +0000 Subject: i2c: Add message transfer tracepoints for SMBUS [ver #2] The SMBUS tracepoints can be enabled thusly: echo 1 >/sys/kernel/debug/tracing/events/i2c/enable and will dump messages that can be viewed in /sys/kernel/debug/tracing/trace that look like: ... smbus_read: i2c-0 a=051 f=0000 c=fa BYTE_DATA ... smbus_reply: i2c-0 a=051 f=0000 c=fa BYTE_DATA l=1 [39] ... smbus_result: i2c-0 a=051 f=0000 c=fa BYTE_DATA rd res=0 formatted as: i2c- a= f= c= res= l= [] The adapters to be traced can be selected by something like: echo adapter_nr==1 >/sys/kernel/debug/tracing/events/i2c/filter Note that this shares the same filter and enablement as i2c. Signed-off-by: David Howells Reviewed-by: Steven Rostedt Signed-off-by: Wolfram Sang --- include/trace/events/i2c.h | 224 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 1 deletion(-) (limited to 'include/trace/events') diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h index 4800207..fe17187 100644 --- a/include/trace/events/i2c.h +++ b/include/trace/events/i2c.h @@ -1,4 +1,4 @@ -/* I2C message transfer tracepoints +/* I2C and SMBUS message transfer tracepoints * * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) @@ -144,6 +144,228 @@ TRACE_EVENT_FN(i2c_result, i2c_transfer_trace_reg, i2c_transfer_trace_unreg); +/* + * i2c_smbus_xfer() write data or procedure call request + */ +TRACE_EVENT_CONDITION(smbus_write, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol, + const union i2c_smbus_data *data), + TP_ARGS(adap, addr, flags, read_write, command, protocol, data), + TP_CONDITION(read_write == I2C_SMBUS_WRITE || + protocol == I2C_SMBUS_PROC_CALL || + protocol == I2C_SMBUS_BLOCK_PROC_CALL), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u8, command ) + __field(__u8, len ) + __field(__u32, protocol ) + __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->command = command; + __entry->protocol = protocol; + + switch (protocol) { + case I2C_SMBUS_BYTE_DATA: + __entry->len = 1; + goto copy; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + __entry->len = 2; + goto copy; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_I2C_BLOCK_DATA: + __entry->len = data->block[0] + 1; + copy: + memcpy(__entry->buf, data->block, __entry->len); + break; + case I2C_SMBUS_QUICK: + case I2C_SMBUS_BYTE: + case I2C_SMBUS_I2C_BLOCK_BROKEN: + default: + __entry->len = 0; + } + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }), + __entry->len, + __entry->len, __entry->buf + )); + +/* + * i2c_smbus_xfer() read data request + */ +TRACE_EVENT_CONDITION(smbus_read, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol), + TP_ARGS(adap, addr, flags, read_write, command, protocol), + TP_CONDITION(!(read_write == I2C_SMBUS_WRITE || + protocol == I2C_SMBUS_PROC_CALL || + protocol == I2C_SMBUS_BLOCK_PROC_CALL)), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, flags ) + __field(__u16, addr ) + __field(__u8, command ) + __field(__u32, protocol ) + __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->command = command; + __entry->protocol = protocol; + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }) + )); + +/* + * i2c_smbus_xfer() read data or procedure call reply + */ +TRACE_EVENT_CONDITION(smbus_reply, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol, + const union i2c_smbus_data *data), + TP_ARGS(adap, addr, flags, read_write, command, protocol, data), + TP_CONDITION(read_write == I2C_SMBUS_READ), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u8, command ) + __field(__u8, len ) + __field(__u32, protocol ) + __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2) ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->command = command; + __entry->protocol = protocol; + + switch (protocol) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + __entry->len = 1; + goto copy; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + __entry->len = 2; + goto copy; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_I2C_BLOCK_DATA: + __entry->len = data->block[0] + 1; + copy: + memcpy(__entry->buf, data->block, __entry->len); + break; + case I2C_SMBUS_QUICK: + case I2C_SMBUS_I2C_BLOCK_BROKEN: + default: + __entry->len = 0; + } + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }), + __entry->len, + __entry->len, __entry->buf + )); + +/* + * i2c_smbus_xfer() result + */ +TRACE_EVENT(smbus_result, + TP_PROTO(const struct i2c_adapter *adap, + u16 addr, unsigned short flags, + char read_write, u8 command, int protocol, + int res), + TP_ARGS(adap, addr, flags, read_write, command, protocol, res), + TP_STRUCT__entry( + __field(int, adapter_nr ) + __field(__u16, addr ) + __field(__u16, flags ) + __field(__u8, read_write ) + __field(__u8, command ) + __field(__s16, res ) + __field(__u32, protocol ) + ), + TP_fast_assign( + __entry->adapter_nr = adap->nr; + __entry->addr = addr; + __entry->flags = flags; + __entry->read_write = read_write; + __entry->command = command; + __entry->protocol = protocol; + __entry->res = res; + ), + TP_printk("i2c-%d a=%03x f=%04x c=%x %s %s res=%d", + __entry->adapter_nr, + __entry->addr, + __entry->flags, + __entry->command, + __print_symbolic(__entry->protocol, + { I2C_SMBUS_QUICK, "QUICK" }, + { I2C_SMBUS_BYTE, "BYTE" }, + { I2C_SMBUS_BYTE_DATA, "BYTE_DATA" }, + { I2C_SMBUS_WORD_DATA, "WORD_DATA" }, + { I2C_SMBUS_PROC_CALL, "PROC_CALL" }, + { I2C_SMBUS_BLOCK_DATA, "BLOCK_DATA" }, + { I2C_SMBUS_I2C_BLOCK_BROKEN, "I2C_BLOCK_BROKEN" }, + { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" }, + { I2C_SMBUS_I2C_BLOCK_DATA, "I2C_BLOCK_DATA" }), + __entry->read_write == I2C_SMBUS_WRITE ? "wr" : "rd", + __entry->res + )); + #endif /* _TRACE_I2C_H */ /* This part must be outside protection */ -- cgit v1.1