diff options
author | Douglas Raillard <douglas.raillard@arm.com> | 2016-11-15 10:39:06 +0000 |
---|---|---|
committer | Sandrine Bailleux <sandrine.bailleux@arm.com> | 2016-12-06 11:49:18 +0000 |
commit | d9b3d26331950a00120bb44a21ee71d157e4d783 (patch) | |
tree | aae758b7558cde7d53678c0acc0055a3ff71db59 | |
parent | eb1c04e80cc7064cbd04ec10bfed4207e8957b77 (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.c | 53 | ||||
-rw-r--r-- | include/lib/timer.h | 17 |
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. |