diff options
author | Patryk Duda <pdk@semihalf.com> | 2021-05-31 20:22:32 +0200 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-06-09 20:17:34 +0000 |
commit | a31e654b7e3271f8b77cea9f3e8051c04c2853d3 (patch) | |
tree | 0ba9b7b21260106f001d9384d9e29b38ab6edaa6 /chip | |
parent | fc9711f65b2c5b51e9bbaa8d36bb799a41a794c2 (diff) | |
download | chrome-ec-a31e654b7e3271f8b77cea9f3e8051c04c2853d3.tar.gz |
stm32/flash-stm32h7: Use udelay() in flash_physical_erase()
Replacing usleep() with udelay() fixes problem with Forced Hard Fault
during rollback_entropy hardware unit test (more precisely, when
rollback entropy is added).
Function rollback_update() calls unlock_rollback() before erasing
rollback region. Surprisingly, unlock_rollback() also disables
interrupts to "minimize time protection is left open". Next
flash_erase() is called and then flash_physical_erase().
If erase operation is not finished, we will call usleep() to yield
CPU to some other task. It sounds good, but remember that interrupts
are still disabled. To switch context we need to use SVCall exception
(see svc_handler()) which is masked when interrupts are disabled.
Sometimes sector was erased before we checked, so no usleep() was
called. That's why it was not reproducing always.
Why Forced Hard Fault occurs when calling SVC with disabled interrupts?
First of all, we need to know that some exceptions have configurable
priority, SVCall belongs to this group (full list can be found at
2.4.2 Exception types PM0253 Rev 5 p.40). Next thing is that we are
using 'CPSID I' instruction to disable interrutps. The instruction
actually sets PRIMASK register (3.12.2 CPS PM0253 Rev 5 p.176). When
PRIMASK register is set it prevents activation of all exceptions with
configurable priority (PM0253 Rev 5 p.25), so SVCall is masked too.
OK! But why we get Forced Hard Fault?
Hard Fault is 'Forced' when some other fault was escalated to Hard Fault
(FORCED bit is set in HFSR register). 2.5.2 Fault escalation and hard
faults PM0253 Rev 5 p.48 provides us information when escalation to Hard
Fault occurs, among others it can occur when "A fault occurs and the
handler for that fault is not enabled".
BUG=b:170432597, b:180761547
BRANCH=none
TEST=Connect icetower using microservo.
sudo servod --board icetower
./test/run_device_tests.py --board dartmonkey
--test rollback_entropy
Make sure that test is passed and no Hard Fault occur.
Signed-off-by: Patryk Duda <pdk@semihalf.com>
Change-Id: I0dc1dae899b81574456a127db9c5e7a498a6f69e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2939676
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Diffstat (limited to 'chip')
-rw-r--r-- | chip/stm32/flash-stm32h7.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/chip/stm32/flash-stm32h7.c b/chip/stm32/flash-stm32h7.c index 6c8c797c41..087ddbf062 100644 --- a/chip/stm32/flash-stm32h7.c +++ b/chip/stm32/flash-stm32h7.c @@ -410,7 +410,12 @@ int crec_flash_physical_erase(int offset, int size) /* Wait for erase to complete */ while ((STM32_FLASH_SR(bank) & FLASH_SR_BUSY) && (get_time().val < deadline.val)) { - usleep(5000); + /* + * Interrupts may not be enabled, so we are using + * udelay() instead of usleep() which can trigger + * Forced Hard Fault (see b/180761547). + */ + udelay(5000); } if (STM32_FLASH_SR(bank) & FLASH_SR_BUSY) { res = EC_ERROR_TIMEOUT; |