From: Mika Kuoppala Subject: 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 Signed-off-by: Mika Kuoppala Signed-off-by: Jean Delvare --- drivers/i2c/Kconfig | 1 + drivers/i2c/i2c-core.c | 12 ++++++------ include/linux/i2c.h | 7 +++---- 3 files changed, 10 insertions(+), 10 deletions(-) --- linux-2.6.32-rc8.orig/drivers/i2c/i2c-core.c 2009-11-23 10:49:08.000000000 +0100 +++ linux-2.6.32-rc8/drivers/i2c/i2c-core.c 2009-11-23 10:49:09.000000000 +0100 @@ -584,7 +584,7 @@ static int i2c_register_adapter(struct i goto out_list; } - mutex_init(&adap->bus_lock); + rt_mutex_init(&adap->bus_lock); /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) @@ -1092,12 +1092,12 @@ int i2c_transfer(struct i2c_adapter *ada #endif if (in_atomic() || irqs_disabled()) { - ret = mutex_trylock(&adap->bus_lock); + ret = rt_mutex_trylock(&adap->bus_lock); if (!ret) /* I2C activity is ongoing. */ return -EAGAIN; } else { - mutex_lock_nested(&adap->bus_lock, adap->level); + rt_mutex_lock(&adap->bus_lock); } /* Retry automatically on arbitration loss */ @@ -1109,7 +1109,7 @@ int i2c_transfer(struct i2c_adapter *ada if (time_after(jiffies, orig_jiffies + adap->timeout)) break; } - mutex_unlock(&adap->bus_lock); + rt_mutex_unlock(&adap->bus_lock); return ret; } else { @@ -1913,7 +1913,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *a flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { - mutex_lock(&adapter->bus_lock); + rt_mutex_lock(&adapter->bus_lock); /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; @@ -1927,7 +1927,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *a orig_jiffies + adapter->timeout)) break; } - mutex_unlock(&adapter->bus_lock); + rt_mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command, protocol, data); --- linux-2.6.32-rc8.orig/include/linux/i2c.h 2009-11-23 10:49:08.000000000 +0100 +++ linux-2.6.32-rc8/include/linux/i2c.h 2009-11-23 10:49:09.000000000 +0100 @@ -338,8 +338,7 @@ struct i2c_adapter { void *algo_data; /* data fields that are valid for all devices */ - u8 level; /* nesting level for lockdep */ - struct mutex bus_lock; + struct rt_mutex bus_lock; int timeout; /* in jiffies */ int retries; @@ -367,7 +366,7 @@ static inline void i2c_set_adapdata(stru */ 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(stru */ 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: */ --- linux-2.6.32-rc8.orig/drivers/i2c/Kconfig 2009-11-23 10:49:08.000000000 +0100 +++ linux-2.6.32-rc8/drivers/i2c/Kconfig 2009-11-23 10:49:09.000000000 +0100 @@ -5,6 +5,7 @@ menuconfig I2C tristate "I2C support" depends on HAS_IOMEM + select RT_MUTEXES ---help--- I2C (pronounce: I-square-C) is a slow serial bus protocol used in many micro controller applications and developed by Philips. SMBus,