summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-04-22 10:45:59 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-04-25 23:06:56 +0000
commit96ef35acba6656bd27aa7e4162d5bafa9e915900 (patch)
tree9dbc5a809e0bcadd79f55cd3d13034c7b89f3d51
parent3ac560d41bf8c225725cdf03c2b4f4d723739d0f (diff)
downloadchrome-ec-96ef35acba6656bd27aa7e4162d5bafa9e915900.tar.gz
cortex-m0: fix hard-faults during software interrupt calls
From time to time (usually under heavy interrupt load), the runtime on Cortex-M0 was panic'ing at the "svc" instruction with a HardFault exception (inside the wait_event() function). The issue was probably the following : the wait_event() code is doing an atomic_read_clear() whose critical section disables interrupts and re-enables them using "cpsie i", then do __schedule() call which is essentially a "svc" instruction. According to ARMv6-m reference manual : "If execution of a CPS instruction: increases the execution priority, the CPS execution serializes that change to the instruction stream. decreases the execution priority, the architecture guarantees only that the new priority is visible to instructions executed after either executing an ISB instruction, or performing an exception entry or exception return." So, when we are executing the "svc", PRIMASK.PM can still be seen as 1 (while it was set to 0 by "cpsie i") and in that case the software interrupt is replaced by a HardFault. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=chrome-os-partner:28296 TEST=run Firefly board under load for extended periods of time. Change-Id: Ie355c36f06e6fe2fee5cca8998a469fa096badad Reviewed-on: https://chromium-review.googlesource.com/196659 Commit-Queue: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r--core/cortex-m0/task.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/core/cortex-m0/task.c b/core/cortex-m0/task.c
index b067e25f62..95b758abb8 100644
--- a/core/cortex-m0/task.c
+++ b/core/cortex-m0/task.c
@@ -329,6 +329,13 @@ static uint32_t __wait_evt(int timeout_us, task_id_t resched)
ASSERT(ret == EC_SUCCESS);
}
while (!(evt = atomic_read_clear(&tsk->events))) {
+ /*
+ * We need to ensure that the execution priority is actually
+ * decreased after the "cpsie i" in the atomic operation above
+ * else the "svc" in the __schedule call below will trigger
+ * a HardFault. Use a barrier to force it at that point.
+ */
+ asm volatile("isb");
/* Remove ourself and get the next task in the scheduler */
__schedule(1, resched);
resched = TASK_ID_IDLE;
@@ -354,10 +361,19 @@ uint32_t task_set_event(task_id_t tskid, uint32_t event, int wait)
need_resched_or_profiling = 1;
#endif
} else {
- if (wait)
+ if (wait) {
return __wait_evt(-1, tskid);
- else
+ } else {
+ /*
+ * We need to ensure that the execution priority is
+ * actually decreased after the "cpsie i" in the atomic
+ * operation above else the "svc" in the __schedule
+ * call below will trigger a HardFault.
+ * Use a barrier to force it at that point.
+ */
+ asm volatile("isb");
__schedule(0, tskid);
+ }
}
return 0;