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 5fb80b8962a2..7c7f4b856bad 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); | |||
62 | static struct device_type i2c_client_type; | 65 | static struct device_type i2c_client_type; |
63 | static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); | 66 | static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); |
64 | 67 | ||
68 | static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; | ||
69 | |||
70 | void i2c_transfer_trace_reg(void) | ||
71 | { | ||
72 | static_key_slow_inc(&i2c_trace_msg); | ||
73 | } | ||
74 | |||
75 | void i2c_transfer_trace_unreg(void) | ||
76 | { | ||
77 | static_key_slow_dec(&i2c_trace_msg); | ||
78 | } | ||
79 | |||
65 | /* ------------------------------------------------------------------------- */ | 80 | /* ------------------------------------------------------------------------- */ |
66 | 81 | ||
67 | static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, | 82 | 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) | |||
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 | } |
1731 | EXPORT_SYMBOL(__i2c_transfer); | 1768 | EXPORT_SYMBOL(__i2c_transfer); |
@@ -1941,6 +1978,13 @@ static int i2c_detect_address(struct i2c_client *temp_client, | |||
1941 | struct i2c_client *client; | 1978 | struct i2c_client *client; |
1942 | 1979 | ||
1943 | /* Detection succeeded, instantiate the device */ | 1980 | /* Detection succeeded, instantiate the device */ |
1981 | if (adapter->class & I2C_CLASS_DEPRECATED) | ||
1982 | dev_warn(&adapter->dev, | ||
1983 | "This adapter will soon drop class based instantiation of devices. " | ||
1984 | "Please make sure client 0x%02x gets instantiated by other means. " | ||
1985 | "Check 'Documentation/i2c/instantiating-devices' for details.\n", | ||
1986 | info.addr); | ||
1987 | |||
1944 | dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", | 1988 | dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", |
1945 | info.type, info.addr); | 1989 | info.type, info.addr); |
1946 | client = i2c_new_device(adapter, &info); | 1990 | client = i2c_new_device(adapter, &info); |
@@ -2521,6 +2565,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, | |||
2521 | int try; | 2565 | int try; |
2522 | s32 res; | 2566 | s32 res; |
2523 | 2567 | ||
2568 | /* If enabled, the following two tracepoints are conditional on | ||
2569 | * read_write and protocol. | ||
2570 | */ | ||
2571 | trace_smbus_write(adapter, addr, flags, read_write, | ||
2572 | command, protocol, data); | ||
2573 | trace_smbus_read(adapter, addr, flags, read_write, | ||
2574 | command, protocol); | ||
2575 | |||
2524 | flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; | 2576 | flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; |
2525 | 2577 | ||
2526 | if (adapter->algo->smbus_xfer) { | 2578 | if (adapter->algo->smbus_xfer) { |
@@ -2541,15 +2593,24 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, | |||
2541 | i2c_unlock_adapter(adapter); | 2593 | i2c_unlock_adapter(adapter); |
2542 | 2594 | ||
2543 | if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) | 2595 | if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) |
2544 | return res; | 2596 | goto trace; |
2545 | /* | 2597 | /* |
2546 | * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't | 2598 | * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't |
2547 | * implement native support for the SMBus operation. | 2599 | * implement native support for the SMBus operation. |
2548 | */ | 2600 | */ |
2549 | } | 2601 | } |
2550 | 2602 | ||
2551 | return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, | 2603 | res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, |
2552 | command, protocol, data); | 2604 | command, protocol, data); |
2605 | |||
2606 | trace: | ||
2607 | /* If enabled, the reply tracepoint is conditional on read_write. */ | ||
2608 | trace_smbus_reply(adapter, addr, flags, read_write, | ||
2609 | command, protocol, data); | ||
2610 | trace_smbus_result(adapter, addr, flags, read_write, | ||
2611 | command, protocol, res); | ||
2612 | |||
2613 | return res; | ||
2553 | } | 2614 | } |
2554 | EXPORT_SYMBOL(i2c_smbus_xfer); | 2615 | EXPORT_SYMBOL(i2c_smbus_xfer); |
2555 | 2616 | ||