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)
|
||||
{
|
||||
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;
|
||||
uint32_t busy_flags;
|
||||
|
||||
|
@ -98,10 +99,16 @@ int flash_stm32_wait_flash_idle(const struct device *dev)
|
|||
#endif
|
||||
|
||||
while ((FLASH_STM32_REGS(dev)->FLASH_STM32_SR & busy_flags)) {
|
||||
if (k_uptime_get() > timeout_time) {
|
||||
LOG_ERR("Timeout! val: %d", STM32_FLASH_TIMEOUT);
|
||||
if (expired) {
|
||||
LOG_ERR("Timeout! val: %d ms", STM32_FLASH_TIMEOUT);
|
||||
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;
|
||||
|
|
|
@ -427,7 +427,8 @@ static int flash_stm32_check_status(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;
|
||||
|
||||
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)
|
||||
#endif
|
||||
{
|
||||
if (k_uptime_get() > timeout_time) {
|
||||
LOG_ERR("Timeout! val: %d", STM32H7_FLASH_TIMEOUT);
|
||||
if (expired) {
|
||||
LOG_ERR("Timeout! val: %d ms", STM32H7_FLASH_TIMEOUT);
|
||||
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue