From 194684e596af4bdaebb424166d94a8aa528edfda Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Sun, 6 Dec 2009 17:06:22 +0100 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 --- include/linux/i2c.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux/i2c.h') diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 7b40cda57a7..52317fb5917 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -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: */ -- cgit v1.2.3-70-g09d2 From c7b25a9e96dc89954ae8d8f473f56fae62030f84 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 6 Dec 2009 17:06:24 +0100 Subject: i2c: Drop probe, ignore and force module parameters The legacy probe and force module parameters are obsolete now, the same can be achieved using the new_device sysfs interface, which is both more flexible and cheaper (it is implemented by i2c-core rather than replicated in every driver module.) The legacy ignore module parameters can be dropped as well. Ignoring can be done by instantiating a "dummy" device at the problematic address. This is the first step of a huge cleanup to i2c-core's i2c_detect function, i2c.h's I2C_CLIENT_INSMOD* macros, and all drivers that made use of them. Signed-off-by: Jean Delvare --- Documentation/i2c/old-module-parameters | 44 ++++++++++++++++ drivers/i2c/i2c-core.c | 65 +---------------------- include/linux/i2c.h | 91 +-------------------------------- 3 files changed, 46 insertions(+), 154 deletions(-) create mode 100644 Documentation/i2c/old-module-parameters (limited to 'include/linux/i2c.h') diff --git a/Documentation/i2c/old-module-parameters b/Documentation/i2c/old-module-parameters new file mode 100644 index 00000000000..8e2b629d533 --- /dev/null +++ b/Documentation/i2c/old-module-parameters @@ -0,0 +1,44 @@ +I2C device driver binding control from user-space +================================================= + +Up to kernel 2.6.32, many i2c drivers used helper macros provided by + which created standard module parameters to let the user +control how the driver would probe i2c buses and attach to devices. These +parameters were known as "probe" (to let the driver probe for an extra +address), "force" (to forcibly attach the driver to a given device) and +"ignore" (to prevent a driver from probing a given address). + +With the conversion of the i2c subsystem to the standard device driver +binding model, it became clear that these per-module parameters were no +longer needed, and that a centralized implementation was possible. The new, +sysfs-based interface is described in the documentation file +"instantiating-devices", section "Method 4: Instantiate from user-space". + +Below is a mapping from the old module parameters to the new interface. + +Attaching a driver to an I2C device +----------------------------------- + +Old method (module parameters): +# modprobe probe=1,0x2d +# modprobe force=1,0x2d +# modprobe force_=1,0x2d + +New method (sysfs interface): +# echo 0x2d > /sys/bus/i2c/devices/i2c-1/new_device + +Preventing a driver from attaching to an I2C device +--------------------------------------------------- + +Old method (module parameters): +# modprobe ignore=1,0x2f + +New method (sysfs interface): +# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device +# modprobe + +Of course, it is important to instantiate the "dummy" device before loading +the driver. The dummy device will be handled by i2c-core itself, preventing +other drivers from binding to it later on. If there is a real device at the +problematic address, and you want another driver to bind to it, then simply +pass the name of the device in question instead of "dummy". diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d664b4a97a3..fdfaebdf3bf 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1259,40 +1259,13 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) return -ENOMEM; temp_client->adapter = adapter; - /* Force entries are done first, and are not affected by ignore - entries */ - if (address_data->forces) { - const unsigned short * const *forces = address_data->forces; - int kind; - - for (kind = 0; forces[kind]; kind++) { - for (i = 0; forces[kind][i] != I2C_CLIENT_END; - i += 2) { - if (forces[kind][i] == adap_id - || forces[kind][i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found force " - "parameter for adapter %d, " - "addr 0x%02x, kind %d\n", - adap_id, forces[kind][i + 1], - kind); - temp_client->addr = forces[kind][i + 1]; - err = i2c_detect_address(temp_client, - kind, driver); - if (err) - goto exit_free; - } - } - } - } - /* Stop here if the classes do not match */ if (!(adapter->class & driver->class)) goto exit_free; /* Stop here if we can't use SMBUS_QUICK */ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { - if (address_data->probe[0] == I2C_CLIENT_END - && address_data->normal_i2c[0] == I2C_CLIENT_END) + if (address_data->normal_i2c[0] == I2C_CLIENT_END) goto exit_free; dev_warn(&adapter->dev, "SMBus Quick command not supported, " @@ -1301,43 +1274,7 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) goto exit_free; } - /* Probe entries are done second, and are not affected by ignore - entries either */ - for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { - if (address_data->probe[i] == adap_id - || address_data->probe[i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found probe parameter for " - "adapter %d, addr 0x%02x\n", adap_id, - address_data->probe[i + 1]); - temp_client->addr = address_data->probe[i + 1]; - err = i2c_detect_address(temp_client, -1, driver); - if (err) - goto exit_free; - } - } - - /* Normal entries are done last, unless shadowed by an ignore entry */ for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { - int j, ignore; - - ignore = 0; - for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; - j += 2) { - if ((address_data->ignore[j] == adap_id || - address_data->ignore[j] == ANY_I2C_BUS) - && address_data->ignore[j + 1] - == address_data->normal_i2c[i]) { - dev_dbg(&adapter->dev, "found ignore " - "parameter for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->ignore[j + 1]); - ignore = 1; - break; - } - } - if (ignore) - continue; - dev_dbg(&adapter->dev, "found normal entry for adapter %d, " "addr 0x%02x\n", adap_id, address_data->normal_i2c[i]); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 52317fb5917..419ab546b26 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -110,7 +110,7 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, * @driver: Device driver model driver * @id_table: List of I2C devices supported by this driver * @detect: Callback for device detection - * @address_data: The I2C addresses to probe, ignore or force (for detect) + * @address_data: The I2C addresses to probe (for detect) * @clients: List of detected clients we created (for i2c-core use only) * * The driver.owner field should be set to the module owner of this driver. @@ -397,9 +397,6 @@ static inline void i2c_unlock_adapter(struct i2c_adapter *adapter) */ struct i2c_client_address_data { const unsigned short *normal_i2c; - const unsigned short *probe; - const unsigned short *ignore; - const unsigned short * const *forces; }; /* Internal numbers to terminate lists */ @@ -613,134 +610,48 @@ union i2c_smbus_data { module_param_array(var, short, &var##_num, 0); \ MODULE_PARM_DESC(var, desc) -#define I2C_CLIENT_MODULE_PARM_FORCE(name) \ -I2C_CLIENT_MODULE_PARM(force_##name, \ - "List of adapter,address pairs which are " \ - "unquestionably assumed to contain a `" \ - # name "' chip") - - #define I2C_CLIENT_INSMOD_COMMON \ -I2C_CLIENT_MODULE_PARM(probe, "List of adapter,address pairs to scan " \ - "additionally"); \ -I2C_CLIENT_MODULE_PARM(ignore, "List of adapter,address pairs not to " \ - "scan"); \ static const struct i2c_client_address_data addr_data = { \ .normal_i2c = normal_i2c, \ - .probe = probe, \ - .ignore = ignore, \ - .forces = forces, \ } -#define I2C_CLIENT_FORCE_TEXT \ - "List of adapter,address pairs to boldly assume to be present" - /* These are the ones you want to use in your own drivers. Pick the one which matches the number of devices the driver differenciates between. */ #define I2C_CLIENT_INSMOD \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -static const unsigned short * const forces[] = { force, NULL }; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_1(chip1) \ enum chips { any_chip, chip1 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, NULL }; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_2(chip1, chip2) \ enum chips { any_chip, chip1, chip2 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip2); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, force_##chip2, NULL }; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_3(chip1, chip2, chip3) \ enum chips { any_chip, chip1, chip2, chip3 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip2); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip3); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, force_##chip2, force_##chip3, NULL }; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_4(chip1, chip2, chip3, chip4) \ enum chips { any_chip, chip1, chip2, chip3, chip4 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip2); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip3); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip4); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, force_##chip2, force_##chip3, \ - force_##chip4, NULL}; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_5(chip1, chip2, chip3, chip4, chip5) \ enum chips { any_chip, chip1, chip2, chip3, chip4, chip5 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip2); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip3); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip4); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip5); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, force_##chip2, force_##chip3, \ - force_##chip4, force_##chip5, NULL }; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_6(chip1, chip2, chip3, chip4, chip5, chip6) \ enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip2); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip3); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip4); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip5); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip6); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, force_##chip2, force_##chip3, \ - force_##chip4, force_##chip5, force_##chip6, NULL }; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_7(chip1, chip2, chip3, chip4, chip5, chip6, chip7) \ enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \ chip7 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip2); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip3); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip4); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip5); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip6); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip7); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, force_##chip2, force_##chip3, \ - force_##chip4, force_##chip5, force_##chip6, \ - force_##chip7, NULL }; \ I2C_CLIENT_INSMOD_COMMON #define I2C_CLIENT_INSMOD_8(chip1, chip2, chip3, chip4, chip5, chip6, chip7, chip8) \ enum chips { any_chip, chip1, chip2, chip3, chip4, chip5, chip6, \ chip7, chip8 }; \ -I2C_CLIENT_MODULE_PARM(force, I2C_CLIENT_FORCE_TEXT); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip1); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip2); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip3); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip4); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip5); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip6); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip7); \ -I2C_CLIENT_MODULE_PARM_FORCE(chip8); \ -static const unsigned short * const forces[] = { force, \ - force_##chip1, force_##chip2, force_##chip3, \ - force_##chip4, force_##chip5, force_##chip6, \ - force_##chip7, force_##chip8, NULL }; \ I2C_CLIENT_INSMOD_COMMON #endif /* __KERNEL__ */ #endif /* _LINUX_I2C_H */ -- cgit v1.2.3-70-g09d2