drivers: flash: Fix timeout handling in STM32 flash driver
Fix timeout error that can occur in rare case. When the thread writing to flash is pre-emptive it can be scheduled out after reading the status register, but before checking if timeout has expired. In this case it will report timeout without re-checking the status register. When writing a lot to flash, for example a firmware update process then this situation is very likely to occur. Signed-off-by: Joakim Andersson <joerchan@gmail.com>
This commit is contained in:
parent
4866cfcc9d
commit
e5093f41b2
2 changed files with 20 additions and 6 deletions
|
@ -81,7 +81,8 @@ static int flash_stm32_check_status(const struct device *dev)
|
||||||
|
|
||||||
int flash_stm32_wait_flash_idle(const struct device *dev)
|
int flash_stm32_wait_flash_idle(const struct device *dev)
|
||||||
{
|
{
|
||||||
int64_t timeout_time = k_uptime_get() + STM32_FLASH_TIMEOUT;
|
k_timepoint_t timeout = sys_timepoint_calc(K_MSEC(STM32_FLASH_TIMEOUT));
|
||||||
|
bool expired = false;
|
||||||
int rc;
|
int rc;
|
||||||
uint32_t busy_flags;
|
uint32_t busy_flags;
|
||||||
|
|
||||||
|
@ -98,10 +99,16 @@ int flash_stm32_wait_flash_idle(const struct device *dev)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while ((FLASH_STM32_REGS(dev)->FLASH_STM32_SR & busy_flags)) {
|
while ((FLASH_STM32_REGS(dev)->FLASH_STM32_SR & busy_flags)) {
|
||||||
if (k_uptime_get() > timeout_time) {
|
if (expired) {
|
||||||
LOG_ERR("Timeout! val: %d", STM32_FLASH_TIMEOUT);
|
LOG_ERR("Timeout! val: %d ms", STM32_FLASH_TIMEOUT);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if expired, but always read status register one more time.
|
||||||
|
* If the calling thread is pre-emptive we may have been scheduled out after reading
|
||||||
|
* the status register, and scheduled back after timeout has expired.
|
||||||
|
*/
|
||||||
|
expired = sys_timepoint_expired(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -427,7 +427,8 @@ static int flash_stm32_check_status(const struct device *dev)
|
||||||
|
|
||||||
int flash_stm32_wait_flash_idle(const struct device *dev)
|
int flash_stm32_wait_flash_idle(const struct device *dev)
|
||||||
{
|
{
|
||||||
int64_t timeout_time = k_uptime_get() + STM32H7_FLASH_TIMEOUT;
|
k_timepoint_t timeout = sys_timepoint_calc(K_MSEC(STM32H7_FLASH_TIMEOUT));
|
||||||
|
bool expired = false;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = flash_stm32_check_status(dev);
|
rc = flash_stm32_check_status(dev);
|
||||||
|
@ -441,10 +442,16 @@ int flash_stm32_wait_flash_idle(const struct device *dev)
|
||||||
while (FLASH_STM32_REGS(dev)->SR1 & FLASH_SR_QW)
|
while (FLASH_STM32_REGS(dev)->SR1 & FLASH_SR_QW)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (k_uptime_get() > timeout_time) {
|
if (expired) {
|
||||||
LOG_ERR("Timeout! val: %d", STM32H7_FLASH_TIMEOUT);
|
LOG_ERR("Timeout! val: %d ms", STM32H7_FLASH_TIMEOUT);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if expired, but always read status register one more time.
|
||||||
|
* If the calling thread is pre-emptive we may have been scheduled out after reading
|
||||||
|
* the status register, and scheduled back after timeout has expired.
|
||||||
|
*/
|
||||||
|
expired = sys_timepoint_expired(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue