aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/i2c/i2c-core.c37
-rw-r--r--include/trace/events/i2c.h150
2 files changed, 187 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);
diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h
new file mode 100644
index 000000000000..4800207269a2
--- /dev/null
+++ b/include/trace/events/i2c.h
@@ -0,0 +1,150 @@
1/* I2C message transfer tracepoints
2 *
3 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#undef TRACE_SYSTEM
12#define TRACE_SYSTEM i2c
13
14#if !defined(_TRACE_I2C_H) || defined(TRACE_HEADER_MULTI_READ)
15#define _TRACE_I2C_H
16
17#include <linux/i2c.h>
18#include <linux/tracepoint.h>
19
20/*
21 * drivers/i2c/i2c-core.c
22 */
23extern void i2c_transfer_trace_reg(void);
24extern void i2c_transfer_trace_unreg(void);
25
26/*
27 * __i2c_transfer() write request
28 */
29TRACE_EVENT_FN(i2c_write,
30 TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
31 int num),
32 TP_ARGS(adap, msg, num),
33 TP_STRUCT__entry(
34 __field(int, adapter_nr )
35 __field(__u16, msg_nr )
36 __field(__u16, addr )
37 __field(__u16, flags )
38 __field(__u16, len )
39 __dynamic_array(__u8, buf, msg->len) ),
40 TP_fast_assign(
41 __entry->adapter_nr = adap->nr;
42 __entry->msg_nr = num;
43 __entry->addr = msg->addr;
44 __entry->flags = msg->flags;
45 __entry->len = msg->len;
46 memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
47 ),
48 TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]",
49 __entry->adapter_nr,
50 __entry->msg_nr,
51 __entry->addr,
52 __entry->flags,
53 __entry->len,
54 __entry->len, __get_dynamic_array(buf)
55 ),
56 i2c_transfer_trace_reg,
57 i2c_transfer_trace_unreg);
58
59/*
60 * __i2c_transfer() read request
61 */
62TRACE_EVENT_FN(i2c_read,
63 TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
64 int num),
65 TP_ARGS(adap, msg, num),
66 TP_STRUCT__entry(
67 __field(int, adapter_nr )
68 __field(__u16, msg_nr )
69 __field(__u16, addr )
70 __field(__u16, flags )
71 __field(__u16, len )
72 ),
73 TP_fast_assign(
74 __entry->adapter_nr = adap->nr;
75 __entry->msg_nr = num;
76 __entry->addr = msg->addr;
77 __entry->flags = msg->flags;
78 __entry->len = msg->len;
79 ),
80 TP_printk("i2c-%d #%u a=%03x f=%04x l=%u",
81 __entry->adapter_nr,
82 __entry->msg_nr,
83 __entry->addr,
84 __entry->flags,
85 __entry->len
86 ),
87 i2c_transfer_trace_reg,
88 i2c_transfer_trace_unreg);
89
90/*
91 * __i2c_transfer() read reply
92 */
93TRACE_EVENT_FN(i2c_reply,
94 TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
95 int num),
96 TP_ARGS(adap, msg, num),
97 TP_STRUCT__entry(
98 __field(int, adapter_nr )
99 __field(__u16, msg_nr )
100 __field(__u16, addr )
101 __field(__u16, flags )
102 __field(__u16, len )
103 __dynamic_array(__u8, buf, msg->len) ),
104 TP_fast_assign(
105 __entry->adapter_nr = adap->nr;
106 __entry->msg_nr = num;
107 __entry->addr = msg->addr;
108 __entry->flags = msg->flags;
109 __entry->len = msg->len;
110 memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
111 ),
112 TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]",
113 __entry->adapter_nr,
114 __entry->msg_nr,
115 __entry->addr,
116 __entry->flags,
117 __entry->len,
118 __entry->len, __get_dynamic_array(buf)
119 ),
120 i2c_transfer_trace_reg,
121 i2c_transfer_trace_unreg);
122
123/*
124 * __i2c_transfer() result
125 */
126TRACE_EVENT_FN(i2c_result,
127 TP_PROTO(const struct i2c_adapter *adap, int num, int ret),
128 TP_ARGS(adap, num, ret),
129 TP_STRUCT__entry(
130 __field(int, adapter_nr )
131 __field(__u16, nr_msgs )
132 __field(__s16, ret )
133 ),
134 TP_fast_assign(
135 __entry->adapter_nr = adap->nr;
136 __entry->nr_msgs = num;
137 __entry->ret = ret;
138 ),
139 TP_printk("i2c-%d n=%u ret=%d",
140 __entry->adapter_nr,
141 __entry->nr_msgs,
142 __entry->ret
143 ),
144 i2c_transfer_trace_reg,
145 i2c_transfer_trace_unreg);
146
147#endif /* _TRACE_I2C_H */
148
149/* This part must be outside protection */
150#include <trace/define_trace.h>