diff options
author | Soby Mathew <soby.mathew@arm.com> | 2016-01-26 11:47:53 +0000 |
---|---|---|
committer | Soby Mathew <soby.mathew@arm.com> | 2016-02-01 14:52:30 +0000 |
commit | 203cdfe26f0c17bf158ced08c71f9e9c99976b96 (patch) | |
tree | 939de78e611784766258a2a9b1449dff846fa946 /services/std_svc/psci/psci_off.c | |
parent | 870d881ced126bd492fe96f6a7bedd0d869dd23a (diff) |
Fix PSCI CPU ON race when setting state to ON_PENDING
When a CPU is powered down using PSCI CPU OFF API, it disables its caches
and updates its `aff_info_state` to OFF. The corresponding cache line is
invalidated by the CPU so that the update will be observed by other CPUs
running with caches enabled. There is a possibility that another CPU
which has been trying to turn ON this CPU via PSCI CPU ON API,
has already seen the update to `aff_info_state` and proceeds to update
the state to ON_PENDING prior to the cache invalidation. This may result
in the update of the state to ON_PENDING being discarded.
This patch fixes this issue by making sure that the update of `aff_info_state`
to ON_PENDING sticks by reading back the value after the cache flush and
retrying it if not updated. The patch also adds a dsbish() to
`psci_do_cpu_off()` to ensure ordering of the update to `aff_info_state`
prior to cache line invalidation.
Fixes ARM-software/tf-issues#349
Change-Id: I225de99957fe89871f8c57bcfc243956e805dcca
Diffstat (limited to 'services/std_svc/psci/psci_off.c')
-rw-r--r-- | services/std_svc/psci/psci_off.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/services/std_svc/psci/psci_off.c b/services/std_svc/psci/psci_off.c index 9ed6f0cf..cef66689 100644 --- a/services/std_svc/psci/psci_off.c +++ b/services/std_svc/psci/psci_off.c @@ -129,10 +129,13 @@ exit: * Set the affinity info state to OFF. This writes directly to * main memory as caches are disabled, so cache maintenance is * required to ensure that later cached reads of aff_info_state - * return AFF_STATE_OFF. + * return AFF_STATE_OFF. A dsbish() ensures ordering of the + * update to the affinity info state prior to cache line + * invalidation. */ flush_cpu_data(psci_svc_cpu_data.aff_info_state); psci_set_aff_info_state(AFF_STATE_OFF); + dsbish(); inv_cpu_data(psci_svc_cpu_data.aff_info_state); /* |