Home | History | Annotate | Download | only in psci
      1 /*
      2  * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are met:
      6  *
      7  * Redistributions of source code must retain the above copyright notice, this
      8  * list of conditions and the following disclaimer.
      9  *
     10  * Redistributions in binary form must reproduce the above copyright notice,
     11  * this list of conditions and the following disclaimer in the documentation
     12  * and/or other materials provided with the distribution.
     13  *
     14  * Neither the name of ARM nor the names of its contributors may be used
     15  * to endorse or promote products derived from this software without specific
     16  * prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
     22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include <arch.h>
     32 #include <arch_helpers.h>
     33 #include <assert.h>
     34 #include <bl_common.h>
     35 #include <bl31.h>
     36 #include <debug.h>
     37 #include <context_mgmt.h>
     38 #include <platform.h>
     39 #include <runtime_svc.h>
     40 #include <stddef.h>
     41 #include "psci_private.h"
     42 
     43 typedef int (*afflvl_on_handler_t)(unsigned long target_cpu,
     44 				 aff_map_node_t *node);
     45 
     46 /*******************************************************************************
     47  * This function checks whether a cpu which has been requested to be turned on
     48  * is OFF to begin with.
     49  ******************************************************************************/
     50 static int cpu_on_validate_state(unsigned int psci_state)
     51 {
     52 	if (psci_state == PSCI_STATE_ON || psci_state == PSCI_STATE_SUSPEND)
     53 		return PSCI_E_ALREADY_ON;
     54 
     55 	if (psci_state == PSCI_STATE_ON_PENDING)
     56 		return PSCI_E_ON_PENDING;
     57 
     58 	assert(psci_state == PSCI_STATE_OFF);
     59 	return PSCI_E_SUCCESS;
     60 }
     61 
     62 /*******************************************************************************
     63  * Handler routine to turn a cpu on. It takes care of any generic, architectural
     64  * or platform specific setup required.
     65  * TODO: Split this code across separate handlers for each type of setup?
     66  ******************************************************************************/
     67 static int psci_afflvl0_on(unsigned long target_cpu,
     68 			   aff_map_node_t *cpu_node)
     69 {
     70 	unsigned long psci_entrypoint;
     71 
     72 	/* Sanity check to safeguard against data corruption */
     73 	assert(cpu_node->level == MPIDR_AFFLVL0);
     74 
     75 	/* Set the secure world (EL3) re-entry point after BL1 */
     76 	psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
     77 
     78 	/*
     79 	 * Plat. management: Give the platform the current state
     80 	 * of the target cpu to allow it to perform the necessary
     81 	 * steps to power on.
     82 	 */
     83 	return psci_plat_pm_ops->affinst_on(target_cpu,
     84 					    psci_entrypoint,
     85 					    cpu_node->level,
     86 					    psci_get_phys_state(cpu_node));
     87 }
     88 
     89 /*******************************************************************************
     90  * Handler routine to turn a cluster on. It takes care or any generic, arch.
     91  * or platform specific setup required.
     92  * TODO: Split this code across separate handlers for each type of setup?
     93  ******************************************************************************/
     94 static int psci_afflvl1_on(unsigned long target_cpu,
     95 			   aff_map_node_t *cluster_node)
     96 {
     97 	unsigned long psci_entrypoint;
     98 
     99 	assert(cluster_node->level == MPIDR_AFFLVL1);
    100 
    101 	/*
    102 	 * There is no generic and arch. specific cluster
    103 	 * management required
    104 	 */
    105 
    106 	/* State management: Is not required while turning a cluster on */
    107 
    108 	/*
    109 	 * Plat. management: Give the platform the current state
    110 	 * of the target cpu to allow it to perform the necessary
    111 	 * steps to power on.
    112 	 */
    113 	psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
    114 	return psci_plat_pm_ops->affinst_on(target_cpu,
    115 					    psci_entrypoint,
    116 					    cluster_node->level,
    117 					    psci_get_phys_state(cluster_node));
    118 }
    119 
    120 /*******************************************************************************
    121  * Handler routine to turn a cluster of clusters on. It takes care or any
    122  * generic, arch. or platform specific setup required.
    123  * TODO: Split this code across separate handlers for each type of setup?
    124  ******************************************************************************/
    125 static int psci_afflvl2_on(unsigned long target_cpu,
    126 			   aff_map_node_t *system_node)
    127 {
    128 	unsigned long psci_entrypoint;
    129 
    130 	/* Cannot go beyond affinity level 2 in this psci imp. */
    131 	assert(system_node->level == MPIDR_AFFLVL2);
    132 
    133 	/*
    134 	 * There is no generic and arch. specific system management
    135 	 * required
    136 	 */
    137 
    138 	/* State management: Is not required while turning a system on */
    139 
    140 	/*
    141 	 * Plat. management: Give the platform the current state
    142 	 * of the target cpu to allow it to perform the necessary
    143 	 * steps to power on.
    144 	 */
    145 	psci_entrypoint = (unsigned long) psci_aff_on_finish_entry;
    146 	return psci_plat_pm_ops->affinst_on(target_cpu,
    147 					    psci_entrypoint,
    148 					    system_node->level,
    149 					    psci_get_phys_state(system_node));
    150 }
    151 
    152 /* Private data structure to make this handlers accessible through indexing */
    153 static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
    154 	psci_afflvl0_on,
    155 	psci_afflvl1_on,
    156 	psci_afflvl2_on,
    157 };
    158 
    159 /*******************************************************************************
    160  * This function takes an array of pointers to affinity instance nodes in the
    161  * topology tree and calls the on handler for the corresponding affinity
    162  * levels
    163  ******************************************************************************/
    164 static int psci_call_on_handlers(aff_map_node_t *target_cpu_nodes[],
    165 				 int start_afflvl,
    166 				 int end_afflvl,
    167 				 unsigned long target_cpu)
    168 {
    169 	int rc = PSCI_E_INVALID_PARAMS, level;
    170 	aff_map_node_t *node;
    171 
    172 	for (level = end_afflvl; level >= start_afflvl; level--) {
    173 		node = target_cpu_nodes[level];
    174 		if (node == NULL)
    175 			continue;
    176 
    177 		/*
    178 		 * TODO: In case of an error should there be a way
    179 		 * of undoing what we might have setup at higher
    180 		 * affinity levels.
    181 		 */
    182 		rc = psci_afflvl_on_handlers[level](target_cpu,
    183 						    node);
    184 		if (rc != PSCI_E_SUCCESS)
    185 			break;
    186 	}
    187 
    188 	return rc;
    189 }
    190 
    191 /*******************************************************************************
    192  * Generic handler which is called to physically power on a cpu identified by
    193  * its mpidr. It traverses through all the affinity levels performing generic,
    194  * architectural, platform setup and state management e.g. for a cpu that is
    195  * to be powered on, it will ensure that enough information is stashed for it
    196  * to resume execution in the non-secure security state.
    197  *
    198  * The state of all the relevant affinity levels is changed after calling the
    199  * affinity level specific handlers as their actions would depend upon the state
    200  * the affinity level is currently in.
    201  *
    202  * The affinity level specific handlers are called in descending order i.e. from
    203  * the highest to the lowest affinity level implemented by the platform because
    204  * to turn on affinity level X it is necessary to turn on affinity level X + 1
    205  * first.
    206  ******************************************************************************/
    207 int psci_afflvl_on(unsigned long target_cpu,
    208 		   entry_point_info_t *ep,
    209 		   int start_afflvl,
    210 		   int end_afflvl)
    211 {
    212 	int rc;
    213 	mpidr_aff_map_nodes_t target_cpu_nodes;
    214 
    215 	/*
    216 	 * This function must only be called on platforms where the
    217 	 * CPU_ON platform hooks have been implemented.
    218 	 */
    219 	assert(psci_plat_pm_ops->affinst_on &&
    220 			psci_plat_pm_ops->affinst_on_finish);
    221 
    222 	/*
    223 	 * Collect the pointers to the nodes in the topology tree for
    224 	 * each affinity instance in the mpidr. If this function does
    225 	 * not return successfully then either the mpidr or the affinity
    226 	 * levels are incorrect.
    227 	 */
    228 	rc = psci_get_aff_map_nodes(target_cpu,
    229 				    start_afflvl,
    230 				    end_afflvl,
    231 				    target_cpu_nodes);
    232 	assert(rc == PSCI_E_SUCCESS);
    233 
    234 	/*
    235 	 * This function acquires the lock corresponding to each affinity
    236 	 * level so that by the time all locks are taken, the system topology
    237 	 * is snapshot and state management can be done safely.
    238 	 */
    239 	psci_acquire_afflvl_locks(start_afflvl,
    240 				  end_afflvl,
    241 				  target_cpu_nodes);
    242 
    243 	/*
    244 	 * Generic management: Ensure that the cpu is off to be
    245 	 * turned on.
    246 	 */
    247 	rc = cpu_on_validate_state(psci_get_state(
    248 				    target_cpu_nodes[MPIDR_AFFLVL0]));
    249 	if (rc != PSCI_E_SUCCESS)
    250 		goto exit;
    251 
    252 	/*
    253 	 * Call the cpu on handler registered by the Secure Payload Dispatcher
    254 	 * to let it do any bookeeping. If the handler encounters an error, it's
    255 	 * expected to assert within
    256 	 */
    257 	if (psci_spd_pm && psci_spd_pm->svc_on)
    258 		psci_spd_pm->svc_on(target_cpu);
    259 
    260 	/* Perform generic, architecture and platform specific handling. */
    261 	rc = psci_call_on_handlers(target_cpu_nodes,
    262 				   start_afflvl,
    263 				   end_afflvl,
    264 				   target_cpu);
    265 
    266 	assert(rc == PSCI_E_SUCCESS || rc == PSCI_E_INTERN_FAIL);
    267 
    268 	/*
    269 	 * This function updates the state of each affinity instance
    270 	 * corresponding to the mpidr in the range of affinity levels
    271 	 * specified.
    272 	 */
    273 	if (rc == PSCI_E_SUCCESS) {
    274 		psci_do_afflvl_state_mgmt(start_afflvl,
    275 					  end_afflvl,
    276 					  target_cpu_nodes,
    277 					  PSCI_STATE_ON_PENDING);
    278 
    279 		/*
    280 		 * Store the re-entry information for the non-secure world.
    281 		 */
    282 		cm_init_context(target_cpu, ep);
    283 	}
    284 
    285 exit:
    286 	/*
    287 	 * This loop releases the lock corresponding to each affinity level
    288 	 * in the reverse order to which they were acquired.
    289 	 */
    290 	psci_release_afflvl_locks(start_afflvl,
    291 				  end_afflvl,
    292 				  target_cpu_nodes);
    293 
    294 	return rc;
    295 }
    296 
    297 /*******************************************************************************
    298  * The following functions finish an earlier affinity power on request. They
    299  * are called by the common finisher routine in psci_common.c.
    300  ******************************************************************************/
    301 static void psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
    302 {
    303 	unsigned int plat_state, state;
    304 
    305 	assert(cpu_node->level == MPIDR_AFFLVL0);
    306 
    307 	/* Ensure we have been explicitly woken up by another cpu */
    308 	state = psci_get_state(cpu_node);
    309 	assert(state == PSCI_STATE_ON_PENDING);
    310 
    311 	/*
    312 	 * Plat. management: Perform the platform specific actions
    313 	 * for this cpu e.g. enabling the gic or zeroing the mailbox
    314 	 * register. The actual state of this cpu has already been
    315 	 * changed.
    316 	 */
    317 
    318 	/* Get the physical state of this cpu */
    319 	plat_state = get_phys_state(state);
    320 	psci_plat_pm_ops->affinst_on_finish(cpu_node->level,
    321 							 plat_state);
    322 
    323 	/*
    324 	 * Arch. management: Enable data cache and manage stack memory
    325 	 */
    326 	psci_do_pwrup_cache_maintenance();
    327 
    328 	/*
    329 	 * All the platform specific actions for turning this cpu
    330 	 * on have completed. Perform enough arch.initialization
    331 	 * to run in the non-secure address space.
    332 	 */
    333 	bl31_arch_setup();
    334 
    335 	/*
    336 	 * Call the cpu on finish handler registered by the Secure Payload
    337 	 * Dispatcher to let it do any bookeeping. If the handler encounters an
    338 	 * error, it's expected to assert within
    339 	 */
    340 	if (psci_spd_pm && psci_spd_pm->svc_on_finish)
    341 		psci_spd_pm->svc_on_finish(0);
    342 
    343 	/*
    344 	 * Generic management: Now we just need to retrieve the
    345 	 * information that we had stashed away during the cpu_on
    346 	 * call to set this cpu on its way.
    347 	 */
    348 	cm_prepare_el3_exit(NON_SECURE);
    349 
    350 	/* Clean caches before re-entering normal world */
    351 	dcsw_op_louis(DCCSW);
    352 }
    353 
    354 static void psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
    355 {
    356 	unsigned int plat_state;
    357 
    358 	assert(cluster_node->level == MPIDR_AFFLVL1);
    359 
    360 	/*
    361 	 * Plat. management: Perform the platform specific actions
    362 	 * as per the old state of the cluster e.g. enabling
    363 	 * coherency at the interconnect depends upon the state with
    364 	 * which this cluster was powered up. If anything goes wrong
    365 	 * then assert as there is no way to recover from this
    366 	 * situation.
    367 	 */
    368 	plat_state = psci_get_phys_state(cluster_node);
    369 	psci_plat_pm_ops->affinst_on_finish(cluster_node->level,
    370 						 plat_state);
    371 }
    372 
    373 
    374 static void psci_afflvl2_on_finish(aff_map_node_t *system_node)
    375 {
    376 	unsigned int plat_state;
    377 
    378 	/* Cannot go beyond this affinity level */
    379 	assert(system_node->level == MPIDR_AFFLVL2);
    380 
    381 	/*
    382 	 * Currently, there are no architectural actions to perform
    383 	 * at the system level.
    384 	 */
    385 
    386 	/*
    387 	 * Plat. management: Perform the platform specific actions
    388 	 * as per the old state of the cluster e.g. enabling
    389 	 * coherency at the interconnect depends upon the state with
    390 	 * which this cluster was powered up. If anything goes wrong
    391 	 * then assert as there is no way to recover from this
    392 	 * situation.
    393 	 */
    394 	plat_state = psci_get_phys_state(system_node);
    395 	psci_plat_pm_ops->affinst_on_finish(system_node->level,
    396 						   plat_state);
    397 }
    398 
    399 const afflvl_power_on_finisher_t psci_afflvl_on_finishers[] = {
    400 	psci_afflvl0_on_finish,
    401 	psci_afflvl1_on_finish,
    402 	psci_afflvl2_on_finish,
    403 };
    404