Commit 194684e5 authored by Mika Kuoppala's avatar Mika Kuoppala Committed by Jean Delvare

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: default avatarPeter Ujfalusi <peter.ujfalusi@nokia.com>
Signed-off-by: default avatarMika Kuoppala <mika.kuoppala@nokia.com>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent a0c11cdd
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
menuconfig I2C menuconfig I2C
tristate "I2C support" tristate "I2C support"
depends on HAS_IOMEM depends on HAS_IOMEM
select RT_MUTEXES
---help--- ---help---
I2C (pronounce: I-square-C) is a slow serial bus protocol used in I2C (pronounce: I-square-C) is a slow serial bus protocol used in
many micro controller applications and developed by Philips. SMBus, many micro controller applications and developed by Philips. SMBus,
......
...@@ -584,7 +584,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -584,7 +584,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
goto out_list; goto out_list;
} }
mutex_init(&adap->bus_lock); rt_mutex_init(&adap->bus_lock);
/* Set default timeout to 1 second if not already set */ /* Set default timeout to 1 second if not already set */
if (adap->timeout == 0) if (adap->timeout == 0)
...@@ -1092,12 +1092,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -1092,12 +1092,12 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
#endif #endif
if (in_atomic() || irqs_disabled()) { if (in_atomic() || irqs_disabled()) {
ret = mutex_trylock(&adap->bus_lock); ret = rt_mutex_trylock(&adap->bus_lock);
if (!ret) if (!ret)
/* I2C activity is ongoing. */ /* I2C activity is ongoing. */
return -EAGAIN; return -EAGAIN;
} else { } else {
mutex_lock_nested(&adap->bus_lock, adap->level); rt_mutex_lock(&adap->bus_lock);
} }
/* Retry automatically on arbitration loss */ /* Retry automatically on arbitration loss */
...@@ -1109,7 +1109,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -1109,7 +1109,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (time_after(jiffies, orig_jiffies + adap->timeout)) if (time_after(jiffies, orig_jiffies + adap->timeout))
break; break;
} }
mutex_unlock(&adap->bus_lock); rt_mutex_unlock(&adap->bus_lock);
return ret; return ret;
} else { } else {
...@@ -1913,7 +1913,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -1913,7 +1913,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
flags &= I2C_M_TEN | I2C_CLIENT_PEC; flags &= I2C_M_TEN | I2C_CLIENT_PEC;
if (adapter->algo->smbus_xfer) { if (adapter->algo->smbus_xfer) {
mutex_lock(&adapter->bus_lock); rt_mutex_lock(&adapter->bus_lock);
/* Retry automatically on arbitration loss */ /* Retry automatically on arbitration loss */
orig_jiffies = jiffies; orig_jiffies = jiffies;
...@@ -1927,7 +1927,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -1927,7 +1927,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
orig_jiffies + adapter->timeout)) orig_jiffies + adapter->timeout))
break; break;
} }
mutex_unlock(&adapter->bus_lock); rt_mutex_unlock(&adapter->bus_lock);
} else } else
res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
command, protocol, data); command, protocol, data);
......
...@@ -338,8 +338,7 @@ struct i2c_adapter { ...@@ -338,8 +338,7 @@ struct i2c_adapter {
void *algo_data; void *algo_data;
/* data fields that are valid for all devices */ /* data fields that are valid for all devices */
u8 level; /* nesting level for lockdep */ struct rt_mutex bus_lock;
struct mutex bus_lock;
int timeout; /* in jiffies */ int timeout; /* in jiffies */
int retries; int retries;
...@@ -367,7 +366,7 @@ static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data) ...@@ -367,7 +366,7 @@ static inline void i2c_set_adapdata(struct i2c_adapter *dev, void *data)
*/ */
static inline void i2c_lock_adapter(struct i2c_adapter *adapter) static inline void i2c_lock_adapter(struct i2c_adapter *adapter)
{ {
mutex_lock(&adapter->bus_lock); rt_mutex_lock(&adapter->bus_lock);
} }
/** /**
...@@ -376,7 +375,7 @@ static inline void i2c_lock_adapter(struct i2c_adapter *adapter) ...@@ -376,7 +375,7 @@ static inline void i2c_lock_adapter(struct i2c_adapter *adapter)
*/ */
static inline void i2c_unlock_adapter(struct i2c_adapter *adapter) static inline void i2c_unlock_adapter(struct i2c_adapter *adapter)
{ {
mutex_unlock(&adapter->bus_lock); rt_mutex_unlock(&adapter->bus_lock);
} }
/*flags for the client struct: */ /*flags for the client struct: */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment