From 42cae5a166c557d0c5809f39d22a351ca58bf1c3 Mon Sep 17 00:00:00 2001 From: Soby Mathew Date: Mon, 11 May 2015 23:15:06 +0100 Subject: [PATCH] PSCI: Set ON_PENDING state early during CPU_ON In the debug build of the function get_power_on_target_afflvl(), there is a check to ensure that the CPU is emerging from a SUSPEND or ON_PENDING state. The state is checked without acquiring the lock for the CPU node. The state could be updated to ON_PENDING in psci_afflvl_on() after the target CPU has been powered up. This results in a race condition which could cause the check for the ON_PENDING state in get_power_on_target_afflvl() to fail. This patch resolves this race condition by setting the state of the target CPU to ON_PENDING before the platform port attempts to power it on. The target CPU is thus guaranteed to read the correct the state. In case the power on operation fails, the state of the CPU is restored to OFF. Fixes ARM-software/tf-issues#302 Change-Id: I3f2306a78c58d47b1a0fb7e33ab04f917a2d5044 --- services/std_svc/psci/psci_afflvl_on.c | 30 ++++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/services/std_svc/psci/psci_afflvl_on.c b/services/std_svc/psci/psci_afflvl_on.c index 0ee03cb5..0dbd0e06 100644 --- a/services/std_svc/psci/psci_afflvl_on.c +++ b/services/std_svc/psci/psci_afflvl_on.c @@ -257,6 +257,16 @@ int psci_afflvl_on(unsigned long target_cpu, if (psci_spd_pm && psci_spd_pm->svc_on) psci_spd_pm->svc_on(target_cpu); + /* + * This function updates the state of each affinity instance + * corresponding to the mpidr in the range of affinity levels + * specified. + */ + psci_do_afflvl_state_mgmt(start_afflvl, + end_afflvl, + target_cpu_nodes, + PSCI_STATE_ON_PENDING); + /* Perform generic, architecture and platform specific handling. */ rc = psci_call_on_handlers(target_cpu_nodes, start_afflvl, @@ -265,23 +275,15 @@ int psci_afflvl_on(unsigned long target_cpu, assert(rc == PSCI_E_SUCCESS || rc == PSCI_E_INTERN_FAIL); - /* - * This function updates the state of each affinity instance - * corresponding to the mpidr in the range of affinity levels - * specified. - */ - if (rc == PSCI_E_SUCCESS) { + if (rc == PSCI_E_SUCCESS) + /* Store the re-entry information for the non-secure world. */ + cm_init_context(target_cpu, ep); + else + /* Restore the state on error. */ psci_do_afflvl_state_mgmt(start_afflvl, end_afflvl, target_cpu_nodes, - PSCI_STATE_ON_PENDING); - - /* - * Store the re-entry information for the non-secure world. - */ - cm_init_context(target_cpu, ep); - } - + PSCI_STATE_OFF); exit: /* * This loop releases the lock corresponding to each affinity level -- 2.30.2