Skip to content

Commit e5093f4

Browse files
joerchankartben
authored andcommitted
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>
1 parent 4866cfc commit e5093f4

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

drivers/flash/flash_stm32.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ static int flash_stm32_check_status(const struct device *dev)
8181

8282
int flash_stm32_wait_flash_idle(const struct device *dev)
8383
{
84-
int64_t timeout_time = k_uptime_get() + STM32_FLASH_TIMEOUT;
84+
k_timepoint_t timeout = sys_timepoint_calc(K_MSEC(STM32_FLASH_TIMEOUT));
85+
bool expired = false;
8586
int rc;
8687
uint32_t busy_flags;
8788

@@ -98,10 +99,16 @@ int flash_stm32_wait_flash_idle(const struct device *dev)
9899
#endif
99100

100101
while ((FLASH_STM32_REGS(dev)->FLASH_STM32_SR & busy_flags)) {
101-
if (k_uptime_get() > timeout_time) {
102-
LOG_ERR("Timeout! val: %d", STM32_FLASH_TIMEOUT);
102+
if (expired) {
103+
LOG_ERR("Timeout! val: %d ms", STM32_FLASH_TIMEOUT);
103104
return -EIO;
104105
}
106+
107+
/* Check if expired, but always read status register one more time.
108+
* If the calling thread is pre-emptive we may have been scheduled out after reading
109+
* the status register, and scheduled back after timeout has expired.
110+
*/
111+
expired = sys_timepoint_expired(timeout);
105112
}
106113

107114
return 0;

drivers/flash/flash_stm32h7x.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,8 @@ static int flash_stm32_check_status(const struct device *dev)
427427

428428
int flash_stm32_wait_flash_idle(const struct device *dev)
429429
{
430-
int64_t timeout_time = k_uptime_get() + STM32H7_FLASH_TIMEOUT;
430+
k_timepoint_t timeout = sys_timepoint_calc(K_MSEC(STM32H7_FLASH_TIMEOUT));
431+
bool expired = false;
431432
int rc;
432433

433434
rc = flash_stm32_check_status(dev);
@@ -441,10 +442,16 @@ int flash_stm32_wait_flash_idle(const struct device *dev)
441442
while (FLASH_STM32_REGS(dev)->SR1 & FLASH_SR_QW)
442443
#endif
443444
{
444-
if (k_uptime_get() > timeout_time) {
445-
LOG_ERR("Timeout! val: %d", STM32H7_FLASH_TIMEOUT);
445+
if (expired) {
446+
LOG_ERR("Timeout! val: %d ms", STM32H7_FLASH_TIMEOUT);
446447
return -EIO;
447448
}
449+
450+
/* Check if expired, but always read status register one more time.
451+
* If the calling thread is pre-emptive we may have been scheduled out after reading
452+
* the status register, and scheduled back after timeout has expired.
453+
*/
454+
expired = sys_timepoint_expired(timeout);
448455
}
449456

450457
return 0;

0 commit comments

Comments
 (0)