eeprom: at24: fix unexpected timeout under high load
authorWang Xin <xin.wang7@cn.bosch.com>
Thu, 16 Aug 2018 17:45:34 +0000 (19:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jul 2019 11:14:46 +0000 (13:14 +0200)
commit64032e2d9ba85819c79b22788d9d155a8320f452
treeea74fc0c4c2bd130996f98df0e6293999610b76e
parentc22cea5a21b236581dd6e43767bfabe533b9001a
eeprom: at24: fix unexpected timeout under high load

commit 9a9e295e7c5c0409c020088b0ae017e6c2b7df6e upstream.

Within at24_loop_until_timeout the timestamp used for timeout checking
is recorded after the I2C transfer and sleep_range(). Under high CPU
load either the execution time for I2C transfer or sleep_range() could
actually be larger than the timeout value. Worst case the I2C transfer
is only tried once because the loop will exit due to the timeout
although the EEPROM is now ready.

To fix this issue the timestamp is recorded at the beginning of each
iteration. That is, before I2C transfer and sleep. Then the timeout
is actually checked against the timestamp of the previous iteration.
This makes sure that even if the timeout is reached, there is still one
more chance to try the I2C transfer in case the EEPROM is ready.

Example:

If you have a system which combines high CPU load with repeated EEPROM
writes you will run into the following scenario.

 - System makes a successful regmap_bulk_write() to EEPROM.
 - System wants to perform another write to EEPROM but EEPROM is still
   busy with the last write.
 - Because of high CPU load the usleep_range() will sleep more than
   25 ms (at24_write_timeout).
 - Within the over-long sleeping the EEPROM finished the previous write
   operation and is ready again.
 - at24_loop_until_timeout() will detect timeout and won't try to write.

Signed-off-by: Wang Xin <xin.wang7@cn.bosch.com>
Signed-off-by: Mark Jonas <mark.jonas@de.bosch.com>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/eeprom/at24.c