summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatryk Duda <pdk@semihalf.com>2021-05-31 20:22:32 +0200
committerCommit Bot <commit-bot@chromium.org>2021-06-09 20:17:34 +0000
commita31e654b7e3271f8b77cea9f3e8051c04c2853d3 (patch)
tree0ba9b7b21260106f001d9384d9e29b38ab6edaa6
parentfc9711f65b2c5b51e9bbaa8d36bb799a41a794c2 (diff)
downloadchrome-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>
-rw-r--r--chip/stm32/flash-stm32h7.c7
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;