summaryrefslogtreecommitdiff
path: root/framework
diff options
context:
space:
mode:
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>2016-04-25 14:14:17 +0100
committerAntonio Nino Diaz <antonio.ninodiaz@arm.com>2016-04-27 09:55:54 +0100
commit32b7578e829fc4086bc8efe2ebfdf603264dbae0 (patch)
treebecb6edbf8a6acb6469b4eecce946ad90cbd77fa /framework
parent1cab674f905a1fb2ce08537aa415f600bf91259b (diff)
Fix TFTF timer tests on FVP Foundation model
When running the TFTF timer test cases on FVP Foundation model sometimes they hang. This only happens when the TFTF is built in debug mode. For the test case stress_test_timer_framework() the following happens: do_stress_test() consists of a loop in which a timer is set up, then the CPU enters suspend mode and the timer IRQ wakes the CPU up. The instant the timers wake up is a random instant based on the current system timer plus a random delay. The reason they failed is that, in debug mode, the debug output sometimes takes too long to complete, as printing text to the console can take a relatively long time. As the Foundation model is using the --use-real-time option, this effect was magnified. During this time, the timer IRQ is sometimes handled, preventing the CPU from waking up. When compiling in release mode, this output isn't printed, so the CPU has enough time to enter suspend mode before the interrupt. IRQs are now masked when trying to enter suspend mode. That way, even if it takes some time to actually enter suspend mode, an early interrupt will become pending and the CPU just won't be able to enter suspend mode. An extra API called `tftf_program_timer_and_suspend` has been added to make it easier to develop other test cases where the CPU may enter suspend mode and a timer is supposed to wake it up. The timer framework used to unconditionally disable IRQs upon entry and enabling them upon exit. This means that IRQs used to always be unmasked, even in the case where they were masked upon entry. This behaviour has been fixed to preserve the DAIF flags instead (their state is saved upon entry and restored upon exit). The test, disabled in a previous commit, has been enabled again. Change-Id: Ia86619a7f30483d77029e583c94265993f578a0f
Diffstat (limited to 'framework')
-rw-r--r--framework/timer/timer_framework.c60
1 files changed, 57 insertions, 3 deletions
diff --git a/framework/timer/timer_framework.c b/framework/timer/timer_framework.c
index 51ec44a..ad22b42 100644
--- a/framework/timer/timer_framework.c
+++ b/framework/timer/timer_framework.c
@@ -37,11 +37,15 @@
#include <irq.h>
#include <platform.h>
#include <platform_def.h>
+#include <power_management.h>
#include <sgi.h>
#include <spinlock.h>
+#include <stddef.h>
+#include <sys/types.h>
#include <tftf.h>
#include <timer.h>
+
/* Helper macros */
#define TIMER_STEP_VALUE (plat_timer_info->timer_step_value)
#define TIMER_IRQ (plat_timer_info->timer_irq)
@@ -149,6 +153,7 @@ int tftf_program_timer(unsigned long time_out_ms)
{
unsigned int core_pos;
unsigned long long current_time;
+ u_register_t flags;
int rc = 0;
/*
@@ -172,6 +177,7 @@ int tftf_program_timer(unsigned long time_out_ms)
/* A timer interrupt request is already available for the core */
assert(interrupt_req_time[core_pos] == INVALID_TIME);
+ flags = read_daif();
disable_irq();
isb();
spin_lock(&timer_lock);
@@ -213,9 +219,55 @@ int tftf_program_timer(unsigned long time_out_ms)
}
spin_unlock(&timer_lock);
- enable_irq();
+ /* Restore DAIF flags */
+ write_daif(flags);
+ isb();
+
+ return rc;
+}
+
+int tftf_program_timer_and_suspend(unsigned long milli_secs,
+ unsigned int pwr_state)
+{
+ int rc;
+ u_register_t flags;
+
+ /* 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.
+ */
+ rc = tftf_program_timer(milli_secs);
+ if (rc == 0) {
+ rc = tftf_cpu_suspend(pwr_state);
+ if (rc != PSCI_E_SUCCESS) {
+ ERROR("%s %d: rc = %d\n", __func__, __LINE__, rc);
+ rc = -1;
+ } else {
+ rc = 0;
+ }
+ } else {
+ ERROR("%s %d: rc = %d\n", __func__, __LINE__, rc);
+ }
+
+ /* 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.
+ */
+
return rc;
}
@@ -224,6 +276,7 @@ int tftf_cancel_timer(void)
unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
unsigned int next_timer_req_core_pos;
unsigned long long current_time;
+ u_register_t flags;
int rc = 0;
/*
@@ -231,6 +284,7 @@ int tftf_cancel_timer(void)
* it will remain pending and a core does not hit IRQ handler trying
* to acquire an already locked spin_lock causing dead lock.
*/
+ flags = read_daif();
disable_irq();
isb();
spin_lock(&timer_lock);
@@ -293,8 +347,8 @@ int tftf_cancel_timer(void)
exit:
spin_unlock(&timer_lock);
- /* Enable IRQ */
- enable_irq();
+ /* Restore DAIF flags */
+ write_daif(flags);
isb();
return rc;