}
/*******************************************************************************
- * This function is passed a cpu_index and the highest level in the topology
- * tree that the operation should be applied to. It picks up locks in order of
- * increasing power domain level in the range specified.
+ * This function is passed the highest level in the topology tree that the
+ * operation should be applied to and a list of node indexes. It picks up locks
+ * from the node index list in order of increasing power domain level in the
+ * range specified.
******************************************************************************/
-void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl, int cpu_idx)
+void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl,
+ const unsigned int *parent_nodes)
{
- unsigned int parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
+ unsigned int parent_idx;
unsigned int level;
/* No locking required for level 0. Hence start locking from level 1 */
for (level = PSCI_CPU_PWR_LVL + 1U; level <= end_pwrlvl; level++) {
+ parent_idx = parent_nodes[level - 1U];
psci_lock_get(&psci_non_cpu_pd_nodes[parent_idx]);
- parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
}
}
/*******************************************************************************
- * This function is passed a cpu_index and the highest level in the topology
- * tree that the operation should be applied to. It releases the locks in order
- * of decreasing power domain level in the range specified.
+ * This function is passed the highest level in the topology tree that the
+ * operation should be applied to and a list of node indexes. It releases the
+ * locks in order of decreasing power domain level in the range specified.
******************************************************************************/
-void psci_release_pwr_domain_locks(unsigned int end_pwrlvl, int cpu_idx)
+void psci_release_pwr_domain_locks(unsigned int end_pwrlvl,
+ const unsigned int *parent_nodes)
{
- unsigned int parent_idx, parent_nodes[PLAT_MAX_PWR_LVL] = {0};
+ unsigned int parent_idx;
unsigned int level;
- /* Get the parent nodes */
- psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
-
/* Unlock top down. No unlocking required for level 0. */
for (level = end_pwrlvl; level >= PSCI_CPU_PWR_LVL + 1U; level--) {
parent_idx = parent_nodes[level - 1U];
{
unsigned int end_pwrlvl;
int cpu_idx = (int) plat_my_core_pos();
+ unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
/*
*/
end_pwrlvl = get_power_on_target_pwrlvl();
+ /* Get the parent nodes */
+ psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
+
/*
* This function acquires the lock corresponding to each power level so
* that by the time all locks are taken, the system topology is snapshot
* and state management can be done safely.
*/
- psci_acquire_pwr_domain_locks(end_pwrlvl, cpu_idx);
+ psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
* This loop releases the lock corresponding to each power level
* in the reverse order to which they were acquired.
*/
- psci_release_pwr_domain_locks(end_pwrlvl, cpu_idx);
+ psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
}
/*******************************************************************************
int rc = PSCI_E_SUCCESS;
int idx = (int) plat_my_core_pos();
psci_power_state_t state_info;
+ unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
/*
* This function must only be called on platforms where the
/* Construct the psci_power_state for CPU_OFF */
psci_set_power_off_state(&state_info);
+ /*
+ * Get the parent nodes here, this is important to do before we
+ * initiate the power down sequence as after that point the core may
+ * have exited coherency and its cache may be disabled, any access to
+ * shared memory after that (such as the parent node lookup in
+ * psci_cpu_pd_nodes) can cause coherency issues on some platforms.
+ */
+ psci_get_parent_pwr_domain_nodes(idx, end_pwrlvl, parent_nodes);
+
/*
* This function acquires the lock corresponding to each power
* level so that by the time all locks are taken, the system topology
* is snapshot and state management can be done safely.
*/
- psci_acquire_pwr_domain_locks(end_pwrlvl, idx);
+ psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
/*
* Call the cpu off handler registered by the Secure Payload Dispatcher
* Release the locks corresponding to each power level in the
* reverse order to which they were acquired.
*/
- psci_release_pwr_domain_locks(end_pwrlvl, idx);
+ psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
/*
* Check if all actions needed to safely power down this cpu have
unsigned int *node_index);
void psci_do_state_coordination(unsigned int end_pwrlvl,
psci_power_state_t *state_info);
-void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl, int cpu_idx);
-void psci_release_pwr_domain_locks(unsigned int end_pwrlvl, int cpu_idx);
+void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl,
+ const unsigned int *parent_nodes);
+void psci_release_pwr_domain_locks(unsigned int end_pwrlvl,
+ const unsigned int *parent_nodes);
int psci_validate_suspend_req(const psci_power_state_t *state_info,
unsigned int is_power_down_state);
unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info);
static void psci_suspend_to_standby_finisher(int cpu_idx,
unsigned int end_pwrlvl)
{
+ unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
psci_power_state_t state_info;
- psci_acquire_pwr_domain_locks(end_pwrlvl,
- cpu_idx);
+ /* Get the parent nodes */
+ psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
+
+ psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
/*
* Find out which retention states this CPU has exited from until the
*/
psci_set_pwr_domains_to_run(end_pwrlvl);
- psci_release_pwr_domain_locks(end_pwrlvl,
- cpu_idx);
+ psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
}
/*******************************************************************************
{
int skip_wfi = 0;
int idx = (int) plat_my_core_pos();
+ unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
/*
* This function must only be called on platforms where the
assert((psci_plat_pm_ops->pwr_domain_suspend != NULL) &&
(psci_plat_pm_ops->pwr_domain_suspend_finish != NULL));
+ /* Get the parent nodes */
+ psci_get_parent_pwr_domain_nodes(idx, end_pwrlvl, parent_nodes);
+
/*
* This function acquires the lock corresponding to each power
* level so that by the time all locks are taken, the system topology
* is snapshot and state management can be done safely.
*/
- psci_acquire_pwr_domain_locks(end_pwrlvl,
- idx);
+ psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
/*
* We check if there are any pending interrupts after the delay
* Release the locks corresponding to each power level in the
* reverse order to which they were acquired.
*/
- psci_release_pwr_domain_locks(end_pwrlvl,
- idx);
+ psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
+
if (skip_wfi == 1)
return;