From 1a21831b3c8ed7925dbbfb3c3b04d90d5a16845d Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 2 Oct 2017 13:28:22 +0200 Subject: i2c: Fix EEPROM driver program timeout handling The RTEMS_MILLISECONDS_TO_TICKS() macro doesn't round up. Do not use it to calculate the program timeout in ticks. Check program done condition after the timeout check to account for pre-emptions. Close #3162. --- cpukit/dev/i2c/eeprom.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'cpukit') diff --git a/cpukit/dev/i2c/eeprom.c b/cpukit/dev/i2c/eeprom.c index 74f2d8c9aa..97e0f55684 100644 --- a/cpukit/dev/i2c/eeprom.c +++ b/cpukit/dev/i2c/eeprom.c @@ -39,7 +39,7 @@ typedef struct { uint32_t size; uint16_t i2c_address_mask; uint16_t i2c_address_shift; - rtems_interval program_timeout; + rtems_interval program_timeout_in_ticks; } eeprom; static uint16_t eeprom_i2c_addr(eeprom *dev, uint32_t off) @@ -172,6 +172,7 @@ static ssize_t eeprom_write( int err; ssize_t m; rtems_interval timeout; + bool before; eeprom_set_addr(dev, off, addr); err = i2c_bus_transfer(dev->base.bus, &msgs[0], RTEMS_ARRAY_SIZE(msgs)); @@ -179,11 +180,16 @@ static ssize_t eeprom_write( return err; } - timeout = rtems_clock_tick_later(dev->program_timeout); + timeout = rtems_clock_tick_later(dev->program_timeout_in_ticks); do { + before = rtems_clock_tick_before(timeout); + m = eeprom_read(&dev->base, &in[0], cur, off); - } while (m != cur && rtems_clock_tick_before(timeout)); + if (m == cur) { + break; + } + } while (before); if (m != cur) { return -ETIMEDOUT; @@ -226,6 +232,7 @@ int i2c_dev_register_eeprom( ) { uint32_t extra_address; + uint32_t ms_per_tick; eeprom *dev; if (address_bytes > EEPROM_MAX_ADDRESS_BYTES) { @@ -261,7 +268,9 @@ int i2c_dev_register_eeprom( dev->address_bytes = address_bytes; dev->page_size = page_size_in_bytes; dev->size = size_in_bytes; - dev->program_timeout = RTEMS_MILLISECONDS_TO_TICKS(program_timeout_in_ms); + ms_per_tick = rtems_configuration_get_milliseconds_per_tick(); + dev->program_timeout_in_ticks = (program_timeout_in_ms + ms_per_tick - 1) + / ms_per_tick + 1; if (extra_address != 0) { dev->i2c_address_mask = extra_address - 1; -- cgit v1.2.3