aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Kuoppala <mika.kuoppala@nokia.com>2009-12-06 11:06:22 -0500
committerJean Delvare <khali@linux-fr.org>2009-12-06 11:06:22 -0500
commit194684e596af4bdaebb424166d94a8aa528edfda (patch)
tree1a6b0ede432e8c9fb4f7a1652deb71044ff9aa50
parenta0c11cdd6a1975fd8d6d186f2e2865a82f3e9bbf (diff)
i2c: Prevent priority inversion on top of bus lock
Low priority thread holding the i2c bus mutex could block higher priority threads to access the bus resulting in unacceptable latencies. Change the mutex type to rt_mutex preventing priority inversion. Tested-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Mika Kuoppala <mika.kuoppala@nokia.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--drivers/i2c/Kconfig1
-rw-r--r--drivers/i2c/i2c-core.c12
-rw-r--r--include/linux/i2c.h7
3 files changed, 10 insertions, 10 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index d7ece131b4f4..8d8a00e5a30e 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -5,6 +5,7 @@
5menuconfig I2C 5menuconfig I2C
6 tristate "I2C support" 6 tristate "I2C support"
7 depends on HAS_IOMEM 7 depends on HAS_IOMEM
8 select RT_MUTEXES
8 ---help--- 9 ---help---
9 I2C (pronounce: I-square-C) is a slow serial bus protocol used in 10 I2C (pronounce: I-square-C) is a slow serial bus protocol used in
10 many micro controller applications and developed by Philips. SMBus, 11 many micro controller applications and developed by Philips. SMBus,
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 296504355142..d664b4a97a31 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -584,7 +584,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
584 goto out_list; 584 goto out_list;
585 } 585 }
586 586
587 mutex_init(&adap->bus_lock); 587 rt_mutex_init(&adap->bus_lock);
588 588
589 /* Set default timeout to 1 second if not already set */ 589 /* Set default timeout to 1 second if not already set */
590 if (adap->timeout == 0) 590 if (adap->timeout == 0)
@@ -1092,12 +1092,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1092#endif 1092#endif
1093 1093
1094 if (in_atomic() || irqs_disabled()) { 1094 if (in_atomic() || irqs_disabled()) {
1095 ret = mutex_trylock(&adap->bus_lock); 1095 ret = rt_mutex_trylock(&adap->bus_lock);
1096 if (!ret) 1096 if (!ret)
1097 /* I2C activity is ongoing. */ 1097 /* I2C activity is ongoing. */
1098 return -EAGAIN; 1098 return -EAGAIN;
1099 } else { 1099 } else {
1100 mutex_lock_nested(&adap->bus_lock, adap->level); 1100 rt_mutex_lock(&adap->bus_lock);
1101 } 1101 }
1102 1102
1103 /* Retry automatically on arbitration loss */ 1103 /* Retry automatically on arbitration loss */
@@ -1109,7 +1109,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
1109 if (time_after(jiffies, orig_jiffies + adap->timeout)) 1109 if (time_after(jiffies, orig_jiffies + adap->timeout))
1110 break; 1110 break;
1111 } 1111 }
1112 mutex_unlock(&adap->bus_lock); 1112 rt_mutex_unlock(&adap->bus_lock);
1113 1113
1114 return ret; 1114 return ret;
1115 } else { 1115 } else {
@@ -1913,7 +1913,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
1913 flags &= I2C_M_TEN | I2C_CLIENT_PEC; 1913 flags &= I2C_M_TEN | I2C_CLIENT_PEC;
1914 1914
1915 if (adapter->algo->smbus_xfer) { 1915 if (adapter->algo->smbus_xfer) {
1916 mutex_lock(&adapter->bus_lock); 1916 rt_mutex_lock(&adapter->bus_lock);
1917 1917
1918 /* Retry automatically on arbitration loss */ 1918 /* Retry automatically on arbitration loss */
1919 orig_jiffies = jiffies; 1919 orig_jiffies = jiffies;
@@ -1927,7 +1927,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
1927 orig_jiffies + adapter->timeout)) 1927 orig_jiffies + adapter->timeout))
1928 break; 1928 break;
1929 } 1929 }
1930 mutex_unlock(&adapter->bus_lock); 1930 rt_mutex_unlock(&adapter->bus_lock);
1931 } else 1931 } else
1932 res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, 1932 res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
1933 command, protocol, data); 1933 command, protocol, data);
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 7b40cda57a70..52317fb5917e 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -338,8 +338,7 @@ struct i2c_adapter {
338 void *algo_data; 338 void *algo_data;
339 339
340 /* data fields that are valid for all devices */ 340 /* data fields that are valid for all devices */
341 u8 level; /* nesting level for lockdep */ 341 struct rt_mutex bus_lock;
342 struct mutex bus_lock;
343 342
344 int timeout; /* in jiffies */ 343 int timeout; /* in jiffies */
345 int retries; 344 int retries;
@@ -367,7 +366,7 @@ static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
367 */ 366 */
368static inline void i2c_lock_adapter(struct i2c_adapter *adapter) 367static inline void i2c_lock_adapter(struct i2c_adapter *adapter)
369{ 368{
370 mutex_lock(&adapter->bus_lock); 369 rt_mutex_lock(&adapter->bus_lock);
371} 370}
372 371
373/** 372/**
@@ -376,7 +375,7 @@ static inline void i2c_lock_adapter(struct i2c_adapter *adapter)
376 */ 375 */
377static inline void i2c_unlock_adapter(struct i2c_adapter *adapter) 376static inline void i2c_unlock_adapter(struct i2c_adapter *adapter)
378{ 377{
379 mutex_unlock(&adapter->bus_lock); 378 rt_mutex_unlock(&adapter->bus_lock);
380} 379}
381 380
382/*flags for the client struct: */ 381/*flags for the client struct: */