aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-03-06 08:35:59 -0500
committerWolfram Sang <wsa@the-dreams.de>2014-03-13 17:12:53 -0400
commitd9a83d62b326574fb4831b64317a82a42642a9a2 (patch)
tree6b195735ecb69aec92374d4034280b4ad2ff5110 /drivers/i2c
parent392debf11656dedd79da44416747d5b2b1747f5e (diff)
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-<adapter-nr> #<message-array-index> a=<addr> f=<flags> l=<datalen> n=<message-array-size> ret=<result> [<data>] 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 <rostedt@goodmis.org> Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Steven Rostedt <rostedt@goodmis.org> [wsa: adapted path for 'enable' in the commit msg] Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/i2c-core.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 98a5fd950f16..bdedbee85c01 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -48,10 +48,13 @@
48#include <linux/rwsem.h> 48#include <linux/rwsem.h>
49#include <linux/pm_runtime.h> 49#include <linux/pm_runtime.h>
50#include <linux/acpi.h> 50#include <linux/acpi.h>
51#include <linux/jump_label.h>
51#include <asm/uaccess.h> 52#include <asm/uaccess.h>
52 53
53#include "i2c-core.h" 54#include "i2c-core.h"
54 55
56#define CREATE_TRACE_POINTS
57#include <trace/events/i2c.h>
55 58
56/* core_lock protects i2c_adapter_idr, and guarantees 59/* core_lock protects i2c_adapter_idr, and guarantees
57 that device detection, deletion of detected devices, and attach_adapter 60 that device detection, deletion of detected devices, and attach_adapter
@@ -62,6 +65,18 @@ static DEFINE_IDR(i2c_adapter_idr);
62static struct device_type i2c_client_type; 65static struct device_type i2c_client_type;
63static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); 66static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
64 67
68static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;
69
70void i2c_transfer_trace_reg(void)
71{
72 static_key_slow_inc(&i2c_trace_msg);
73}
74
75void i2c_transfer_trace_unreg(void)
76{
77 static_key_slow_dec(&i2c_trace_msg);
78}
79
65/* ------------------------------------------------------------------------- */ 80/* ------------------------------------------------------------------------- */
66 81
67static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, 82static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
@@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void)
1686 class_compat_unregister(i2c_adapter_compat_class); 1701 class_compat_unregister(i2c_adapter_compat_class);
1687#endif 1702#endif
1688 bus_unregister(&i2c_bus_type); 1703 bus_unregister(&i2c_bus_type);
1704 tracepoint_synchronize_unregister();
1689} 1705}
1690 1706
1691/* We must initialize early, because some subsystems register i2c drivers 1707/* We must initialize early, because some subsystems register i2c drivers
@@ -1716,6 +1732,19 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1716 unsigned long orig_jiffies; 1732 unsigned long orig_jiffies;
1717 int ret, try; 1733 int ret, try;
1718 1734
1735 /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
1736 * enabled. This is an efficient way of keeping the for-loop from
1737 * being executed when not needed.
1738 */
1739 if (static_key_false(&i2c_trace_msg)) {
1740 int i;
1741 for (i = 0; i < num; i++)
1742 if (msgs[i].flags & I2C_M_RD)
1743 trace_i2c_read(adap, &msgs[i], i);
1744 else
1745 trace_i2c_write(adap, &msgs[i], i);
1746 }
1747
1719 /* Retry automatically on arbitration loss */ 1748 /* Retry automatically on arbitration loss */
1720 orig_jiffies = jiffies; 1749 orig_jiffies = jiffies;
1721 for (ret = 0, try = 0; try <= adap->retries; try++) { 1750 for (ret = 0, try = 0; try <= adap->retries; try++) {
@@ -1726,6 +1755,14 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1726 break; 1755 break;
1727 } 1756 }
1728 1757
1758 if (static_key_false(&i2c_trace_msg)) {
1759 int i;
1760 for (i = 0; i < ret; i++)
1761 if (msgs[i].flags & I2C_M_RD)
1762 trace_i2c_reply(adap, &msgs[i], i);
1763 trace_i2c_result(adap, i, ret);
1764 }
1765
1729 return ret; 1766 return ret;
1730} 1767}
1731EXPORT_SYMBOL(__i2c_transfer); 1768EXPORT_SYMBOL(__i2c_transfer);