summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Raillard <douglas.raillard@arm.com>2016-11-15 10:39:06 +0000
committerSandrine Bailleux <sandrine.bailleux@arm.com>2016-12-06 11:49:18 +0000
commitd9b3d26331950a00120bb44a21ee71d157e4d783 (patch)
treeaae758b7558cde7d53678c0acc0055a3ff71db59
parenteb1c04e80cc7064cbd04ec10bfed4207e8957b77 (diff)
Add timer safe version of system suspend helper
Add function to safely program a timer and issue a system suspend PSCI call in the same way as tftf_program_timer_and_suspend. It exposes the return code of the timer setup and system suspend PSCI call through output parameters. Change-Id: Iea6587ca8f6fc9bac92faed90d8b531aa9a9f46a Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
-rw-r--r--framework/timer/timer_framework.c53
-rw-r--r--include/lib/timer.h17
2 files changed, 70 insertions, 0 deletions
diff --git a/framework/timer/timer_framework.c b/framework/timer/timer_framework.c
index 4adff6f..178f67c 100644
--- a/framework/timer/timer_framework.c
+++ b/framework/timer/timer_framework.c
@@ -271,6 +271,59 @@ int tftf_program_timer_and_suspend(unsigned long milli_secs,
return rc;
}
+int tftf_program_timer_and_sys_suspend(unsigned long milli_secs,
+ int *timer_rc, int *suspend_rc)
+{
+ int rc = 0;
+ u_register_t flags;
+
+ /* Default to successful return codes */
+ int timer_rc_val = 0;
+ int suspend_rc_val = PSCI_E_SUCCESS;
+
+ /* Preserve DAIF flags. IRQs need to be disabled for this to work. */
+ flags = read_daif();
+ disable_irq();
+ isb();
+
+ /*
+ * Even with IRQs masked, the timer IRQ will wake the CPU up.
+ *
+ * If the timer IRQ happens before entering suspend mode (because the
+ * timer took too long to program, for example) the fact that the IRQ is
+ * pending will prevent the CPU from entering suspend mode and not being
+ * able to wake up.
+ */
+ timer_rc_val = tftf_program_timer(milli_secs);
+ if (timer_rc_val == 0) {
+ suspend_rc_val = tftf_system_suspend();
+ if (suspend_rc_val != PSCI_E_SUCCESS) {
+ rc = -1;
+ INFO("%s %d: suspend_rc = %d\n", __func__, __LINE__,
+ suspend_rc_val);
+ }
+ } else {
+ rc = -1;
+ INFO("%s %d: timer_rc = %d\n", __func__, __LINE__, timer_rc_val);
+ }
+
+ /* Restore previous DAIF flags */
+ write_daif(flags);
+ isb();
+
+ /*
+ * If IRQs were disabled when calling this function, the timer IRQ
+ * handler won't be called and the timer interrupt will be pending, but
+ * that isn't necessarily a problem.
+ */
+ if (timer_rc)
+ *timer_rc = timer_rc_val;
+ if (suspend_rc)
+ *suspend_rc = suspend_rc_val;
+
+ return rc;
+}
+
int tftf_timer_sleep(unsigned long milli_secs)
{
int ret, power_state;
diff --git a/include/lib/timer.h b/include/lib/timer.h
index 1c12354..7385d9b 100644
--- a/include/lib/timer.h
+++ b/include/lib/timer.h
@@ -76,6 +76,23 @@ int tftf_program_timer_and_suspend(unsigned long milli_secs,
unsigned int pwr_state);
/*
+ * Requests the timer framework to send an interrupt after milli_secs and to
+ * suspend the system. The interrupt is sent to the calling core of this api.
+ * The actual time the interrupt is received by the core can be greater than
+ * the requested time. For the system suspend to succeed, all cores other than
+ * the calling core should be in the OFF state.
+ *
+ * Return codes from tftf_program_timer calls and tftf_cpu_system suspend
+ * are stored respectively in timer_rc and suspend_rc output parameters.
+ * If a function is not executed, the return value stored in the output
+ * parameters will be as if the correponding call succeeded. NULL pointers are
+ * accepted to discard the return codes.
+ * Returns 0 on success and -1 on failure.
+ */
+int tftf_program_timer_and_sys_suspend(unsigned long milli_secs,
+ int *timer_rc, int *suspend_rc);
+
+/*
* Suspends the calling CPU for specified milliseconds.
*
* Returns 0 on success, and -1 otherwise.