diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h index 8b4d692fe..645729cc2 100644 --- a/os/hal/include/i2c.h +++ b/os/hal/include/i2c.h @@ -102,7 +102,7 @@ typedef enum { */ #define i2cMasterTransmit(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes) \ (i2cMasterTransmitTimeout(i2cp, addr, txbuf, txbytes, rxbuf, rxbytes, \ - TIME_INFINITE)) + TIME_INFINITE)) /** * @brief Wrap i2cMasterReceiveTimeout function with TIME_INFINITE timeout. diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index 7458d9252..229520a91 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -165,13 +165,15 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) { static void i2c_lld_safety_timeout(void *p) { I2CDriver *i2cp = (I2CDriver *)p; + chSysLockFromIsr(); if (i2cp->thread) { + Thread *tp = i2cp->thread; i2c_lld_abort_operation(i2cp); - chSysLockFromIsr(); - i2cp->thread->p_u.rdymsg = RDY_TIMEOUT; - chSchReadyI(i2cp->thread); - chSysUnlockFromIsr(); + i2cp->thread = NULL; + tp->p_u.rdymsg = RDY_TIMEOUT; + chSchReadyI(tp); } + chSysUnlockFromIsr(); } /** @@ -768,12 +770,12 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, systime_t timeout) { I2C_TypeDef *dp = i2cp->i2c; VirtualTimer vt; - msg_t rdymsg; chDbgCheck((rxbytes > 1), "i2c_lld_master_receive_timeout"); /* Global timeout for the whole operation.*/ - chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); /* Releases the lock from high level driver.*/ chSysUnlock(); @@ -789,10 +791,10 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits until BUSY flag is reset and the STOP from the previous operation is completed, alternatively for a timeout condition.*/ while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) { - if (!chVTIsArmedI(&vt)) { - chSysLock(); + chSysLock(); + if (!chVTIsArmedI(&vt)) return RDY_TIMEOUT; - } + chSysUnlock(); } /* This lock will be released in high level driver.*/ @@ -810,11 +812,10 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits for the operation completion or a timeout.*/ i2cp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); - rdymsg = chThdSelf()->p_u.rdymsg; - if (rdymsg != RDY_TIMEOUT) + if (chVTIsArmedI(&vt)) chVTResetI(&vt); - return rdymsg; + return chThdSelf()->p_u.rdymsg; } /** @@ -848,13 +849,13 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, systime_t timeout) { I2C_TypeDef *dp = i2cp->i2c; VirtualTimer vt; - msg_t rdymsg; chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))), "i2c_lld_master_transmit_timeout"); /* Global timeout for the whole operation.*/ - chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); + if (timeout != TIME_INFINITE) + chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); /* Releases the lock from high level driver.*/ chSysUnlock(); @@ -874,10 +875,10 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits until BUSY flag is reset and the STOP from the previous operation is completed, alternatively for a timeout condition.*/ while ((dp->SR2 & I2C_SR2_BUSY) || (dp->CR1 & I2C_CR1_STOP)) { - if (!chVTIsArmedI(&vt)) { - chSysLock(); + chSysLock(); + if (!chVTIsArmedI(&vt)) return RDY_TIMEOUT; - } + chSysUnlock(); } /* This lock will be released in high level driver.*/ @@ -895,11 +896,10 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, /* Waits for the operation completion or a timeout.*/ i2cp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); - rdymsg = chThdSelf()->p_u.rdymsg; - if (rdymsg != RDY_TIMEOUT) + if (chVTIsArmedI(&vt)) chVTResetI(&vt); - return rdymsg; + return chThdSelf()->p_u.rdymsg; } #endif /* HAL_USE_I2C */ diff --git a/readme.txt b/readme.txt index 75cc23fe0..c20f296f5 100644 --- a/readme.txt +++ b/readme.txt @@ -81,6 +81,8 @@ ***************************************************************************** *** 2.5.0 *** +- FIX: Fixed timeout related race condition in STM32 I2C driver (bug 3530043) + (backported to 2.4.2). - FIX: Fixed wrong macro check in STM32 MAC driver (bug 3527179)(backported to 2.4.2). - FIX: Fixed error in STM32L-Discovery board.h file (bug 3526918)(backported