i2c: Prevent priority inversion on top of bus lock
authorMika Kuoppala <mika.kuoppala@nokia.com>
Sun, 6 Dec 2009 16:06:22 +0000 (17:06 +0100)
committerJean Delvare <khali@linux-fr.org>
Sun, 6 Dec 2009 16:06:22 +0000 (17:06 +0100)
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>
drivers/i2c/Kconfig
drivers/i2c/i2c-core.c
include/linux/i2c.h

index d7ece13..8d8a00e 100644 (file)
@@ -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,
index 2965043..d664b4a 100644 (file)
@@ -584,7 +584,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
                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 *adap, struct i2c_msg *msgs, int num)
 #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 *adap, struct i2c_msg *msgs, int num)
                        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 *adapter, u16 addr, unsigned short flags,
        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 *adapter, u16 addr, unsigned short flags,
                                       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);
index 7b40cda..52317fb 100644 (file)
@@ -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(struct i2c_adapter *dev, void *data)
  */
 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)
  */
 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: */