summaryrefslogtreecommitdiff
path: root/core/cortex-m0/irq_handler.h
diff options
context:
space:
mode:
authorAlexandru M Stan <amstan@chromium.org>2015-02-06 15:47:43 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-02-12 06:44:04 +0000
commit80778ad0eb0f2a7a156f02b68eb7103687c245fb (patch)
tree4d728471e57e23e5f7ce4b9898707088a5e6e18b /core/cortex-m0/irq_handler.h
parent39b111437ce89d2e90f9c3891922834b723b0878 (diff)
downloadchrome-ec-80778ad0eb0f2a7a156f02b68eb7103687c245fb.tar.gz
cortex-m0: Add deferred scheduler
If 2 interrupts happen at the same time, there is a chance that the nested interrupt will not call svc_handler when it needs to. In extreme cases this could lead to tasks not getting woken up when they're supposed to and watchdog resetting. The reason stuff worked was because there were enough other interrupts around to eventually call the scheduler and switch to the ready task. This change modifies the interrupt calls to not call the scheduler directly (because in nested interrupt situation this causes problems), but defer the call to scheduling until after the irq finishes by triggering a low priority interrupt which will for sure call svc_host at the end. The PendSV irq was used for this purpose. BUG=chrome-os-partner:36193 TEST=No more SPI errors caused by scheduler problems TEST=usleeps now are more accurate, they're guaranteed to not take forever now BRANCH=veyron Change-Id: I42acde6b3eb7be2540a0de9a8562dee2ea2be7ab Signed-off-by: Alexandru M Stan <amstan@chromium.org> Signed-off-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/248902 Tested-by: Alec Berg <alecaberg@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org> Commit-Queue: Alec Berg <alecaberg@chromium.org>
Diffstat (limited to 'core/cortex-m0/irq_handler.h')
-rw-r--r--core/cortex-m0/irq_handler.h53
1 files changed, 14 insertions, 39 deletions
diff --git a/core/cortex-m0/irq_handler.h b/core/cortex-m0/irq_handler.h
index 442c20ac00..f6742f5c82 100644
--- a/core/cortex-m0/irq_handler.h
+++ b/core/cortex-m0/irq_handler.h
@@ -8,60 +8,35 @@
#ifndef __IRQ_HANDLER_H
#define __IRQ_HANDLER_H
-#ifdef CONFIG_TASK_PROFILING
-#define bl_task_start_irq_handler "bl task_start_irq_handler\n"
-#else
-#define bl_task_start_irq_handler ""
-#endif
+#include "cpu.h"
/* Helper macros to build the IRQ handler and priority struct names */
#define IRQ_HANDLER(irqname) CONCAT3(irq_, irqname, _handler)
#define IRQ_PRIORITY(irqname) CONCAT2(prio_, irqname)
-/* re-scheduling flag */
-extern int need_resched_or_profiling;
-
/*
* Macro to connect the interrupt handler "routine" to the irq number "irq" and
* ensure it is enabled in the interrupt controller with the right priority.
*/
#define DECLARE_IRQ(irq, routine, priority) DECLARE_IRQ_(irq, routine, priority)
+#ifdef CONFIG_TASK_PROFILING
#define DECLARE_IRQ_(irq, routine, priority) \
- void IRQ_HANDLER(irq)(void) __attribute__((naked)); \
void IRQ_HANDLER(irq)(void) \
{ \
- asm volatile("mov r0, lr\n" \
- /* Must push registers in pairs to keep 64-bit aligned*/\
- /* stack for ARM EABI. */ \
- "push {r0, %0}\n" \
- bl_task_start_irq_handler \
- "bl "#routine"\n" \
- "pop {r2, r3}\n" \
- /* read need_resched_or_profiling result after IRQ */ \
- "ldr r0, [r3]\n" \
- "mov r1, #8\n" \
- "cmp r0, #0\n" \
- /* if we need to go through the re-scheduling, go on */ \
- "bne 2f\n" \
- /* else return from exception */ \
- "1: bx r2\n" \
- /* check if that's a nested exception */ \
- "2: tst r1, r2\n" \
- /* if yes return immediatly */ \
- "beq 1b\n" \
- "push {r0, r2}\n" \
- "mov r0, #0\n" \
- "mov r1, #0\n" \
- /* ensure we have priority 0 during re-scheduling */ \
- "cpsid i\n isb\n" \
- /* re-schedule the highest priority task */ \
- "bl svc_handler\n" \
- /* enable interrupts and return from exception */ \
- "cpsie i\n" \
- "pop {r0,pc}\n" \
- : : "r"(&need_resched_or_profiling)); \
+ void *ret = __builtin_return_address(0); \
+ task_start_irq_handler(ret); \
+ routine(); \
+ task_end_irq_handler(ret); \
} \
const struct irq_priority IRQ_PRIORITY(irq) \
__attribute__((section(".rodata.irqprio"))) \
= {irq, priority}
+#else /* CONFIG_TASK_PROFILING */
+/* No Profiling : connect directly the IRQ vector */
+#define DECLARE_IRQ_(irq, routine, priority) \
+ void IRQ_HANDLER(irq)(void) __attribute__((alias(STRINGIFY(routine))));\
+ const struct irq_priority IRQ_PRIORITY(irq) \
+ __attribute__((section(".rodata.irqprio"))) \
+ = {irq, priority}
+#endif /* CONFIG_TASK_PROFILING */
#endif /* __IRQ_HANDLER_H */