diff options
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5fb80b8..7c7f4b8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,10 +48,13 @@ #include <linux/rwsem.h> #include <linux/pm_runtime.h> #include <linux/acpi.h> +#include <linux/jump_label.h> #include <asm/uaccess.h> #include "i2c-core.h" +#define CREATE_TRACE_POINTS +#include <trace/events/i2c.h> /* core_lock protects i2c_adapter_idr, and guarantees that device detection, deletion of detected devices, and attach_adapter @@ -62,6 +65,18 @@ static DEFINE_IDR(i2c_adapter_idr); static struct device_type i2c_client_type; static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); +static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; + +void i2c_transfer_trace_reg(void) +{ + static_key_slow_inc(&i2c_trace_msg); +} + +void i2c_transfer_trace_unreg(void) +{ + static_key_slow_dec(&i2c_trace_msg); +} + /* ------------------------------------------------------------------------- */ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, @@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void) class_compat_unregister(i2c_adapter_compat_class); #endif bus_unregister(&i2c_bus_type); + tracepoint_synchronize_unregister(); } /* 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) unsigned long orig_jiffies; int ret, try; + /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets + * enabled. This is an efficient way of keeping the for-loop from + * being executed when not needed. + */ + if (static_key_false(&i2c_trace_msg)) { + int i; + for (i = 0; i < num; i++) + if (msgs[i].flags & I2C_M_RD) + trace_i2c_read(adap, &msgs[i], i); + else + trace_i2c_write(adap, &msgs[i], i); + } + /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; 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) break; } + if (static_key_false(&i2c_trace_msg)) { + int i; + for (i = 0; i < ret; i++) + if (msgs[i].flags & I2C_M_RD) + trace_i2c_reply(adap, &msgs[i], i); + trace_i2c_result(adap, i, ret); + } + return ret; } EXPORT_SYMBOL(__i2c_transfer); @@ -1941,6 +1978,13 @@ static int i2c_detect_address(struct i2c_client *temp_client, struct i2c_client *client; /* Detection succeeded, instantiate the device */ + if (adapter->class & I2C_CLASS_DEPRECATED) + dev_warn(&adapter->dev, + "This adapter will soon drop class based instantiation of devices. " + "Please make sure client 0x%02x gets instantiated by other means. " + "Check 'Documentation/i2c/instantiating-devices' for details.\n", + info.addr); + dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", info.type, info.addr); client = i2c_new_device(adapter, &info); @@ -2521,6 +2565,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, int try; s32 res; + /* If enabled, the following two tracepoints are conditional on + * read_write and protocol. + */ + trace_smbus_write(adapter, addr, flags, read_write, + command, protocol, data); + trace_smbus_read(adapter, addr, flags, read_write, + command, protocol); + flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; if (adapter->algo->smbus_xfer) { @@ -2541,15 +2593,24 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, i2c_unlock_adapter(adapter); if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) - return res; + goto trace; /* * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't * implement native support for the SMBus operation. */ } - return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, - command, protocol, data); + res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, + command, protocol, data); + +trace: + /* If enabled, the reply tracepoint is conditional on read_write. */ + trace_smbus_reply(adapter, addr, flags, read_write, + command, protocol, data); + trace_smbus_result(adapter, addr, flags, read_write, + command, protocol, res); + + return res; } EXPORT_SYMBOL(i2c_smbus_xfer); |