14

I'm writing a multithread C program in embedded Linux that accesses from userspace a number of I2C devices (slaves). Also, I access the same I2C device from multiple threads. I'm using SMBUS functions (i2c_smbus_write_byte_data, i2c_smbus_read_byte_data, i2c_smbus_read_i2c_block_data,...).

Is there any protection from concurrent access built in or do I need to add mutexes myself?

For instance: I have a Read function that read data from one sensor over I2C. But the same function can be called from another thread as well, resulting in possible concurrent access. Do I have to use some static mutex in that function or is it already in the I2C access functions?

stef
  • 737
  • 4
  • 13
  • 31
  • From memory, I2C drivers are protected against concurrent access - but I would recommend having a look at the kernel source to be sure. This only holds of course if your access to the device retains arbitration or has no multi-transaction state. – marko May 14 '13 at 15:15

2 Answers2

18

I2C is a shared bus with multiple devices, which could be accessed from multiple processes as well as threads. So the Linux I2C driver code uses a mutex to manage access to each I2C bus.

For SMBus functions, see the Linux kernel function i2c_smbus_xfer() in i2c-core-smbus.c. It gets a lock for the I2C adapter before beginning a transfer (look at the source code, and see the call to __i2c_lock_bus_helper()). All SMBus transactions are based on that function.

For I2C functions, see the Linux kernel function i2c_transfer() in i2c-core-base.c. It gets a lock for the I2C adapter before beginning a transfer. All I2C transaction are based on that function.

So yes, there is protection from concurrent access built-in.

(links are for Linux kernel 5.13)

Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
  • If you follow the `i2c_smbus_xfer` path, you end up at [struct i2c_lock_operations](https://elixir.bootlin.com/linux/latest/source/include/linux/i2c.h#L562) which seems to leave the implementation details of the locking mechanism to the `i2c_adapter`... Where is this mutex that you are referring to? – mallwright Jun 07 '20 at 15:50
  • As I said, see the call to `i2c_lock_adapter(adapter)`... which in turn calls `rt_mutex_lock(&adapter->bus_lock)`. – Craig McQueen Jun 07 '20 at 20:24
  • Could you be specific regarding which version of the kernel you are referring to and include the file and line number? Looking at the latest (5.7.1 at the time of writing) and as far as I can tell, the locking logic becomes implementation dependent after calling the `lock_bus` function specified in the `i2c_lock_operations` struct via [adapter->lock_ops->lock_bus(adapter, flags);](https://elixir.bootlin.com/linux/v5.7.1/source/include/linux/i2c.h#L785) – mallwright Jun 08 '20 at 13:58
  • I can see the `struct rt_mutex bus_lock;` member of `struct i2c_adapter` but nothing in include/linux/i2c.h touches it... – mallwright Jun 08 '20 at 14:03
-1

Use a mutex in your program. The driver has no way to know the operations that each thread is going to do.

Ottavio Campana
  • 4,088
  • 5
  • 31
  • 58