| 
									
										
										
										
											2013-05-21 14:24:11 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2012 ARM Limited | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author: Will Deacon <will.deacon@arm.com> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/smp.h>
 | 
					
						
							|  |  |  | #include <linux/of.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/psci.h>
 | 
					
						
							|  |  |  | #include <asm/smp_plat.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * psci_smp assumes that the following is true about PSCI: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * cpu_suspend   Suspend the execution on a CPU | 
					
						
							|  |  |  |  * @state        we don't currently describe affinity levels, so just pass 0. | 
					
						
							|  |  |  |  * @entry_point  the first instruction to be executed on return | 
					
						
							|  |  |  |  * returns 0  success, < 0 on failure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * cpu_off       Power down a CPU | 
					
						
							|  |  |  |  * @state        we don't currently describe affinity levels, so just pass 0. | 
					
						
							|  |  |  |  * no return on successful call | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * cpu_on        Power up a CPU | 
					
						
							|  |  |  |  * @cpuid        cpuid of target CPU, as from MPIDR | 
					
						
							|  |  |  |  * @entry_point  the first instruction to be executed on return | 
					
						
							|  |  |  |  * returns 0  success, < 0 on failure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * migrate       Migrate the context to a different CPU | 
					
						
							|  |  |  |  * @cpuid        cpuid of target CPU, as from MPIDR | 
					
						
							|  |  |  |  * returns 0  success, < 0 on failure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern void secondary_startup(void); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-17 15:43:14 -04:00
										 |  |  | static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) | 
					
						
							| 
									
										
										
										
											2013-05-21 14:24:11 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (psci_ops.cpu_on) | 
					
						
							|  |  |  | 		return psci_ops.cpu_on(cpu_logical_map(cpu), | 
					
						
							|  |  |  | 				       __pa(secondary_startup)); | 
					
						
							|  |  |  | 	return -ENODEV; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_HOTPLUG_CPU
 | 
					
						
							|  |  |  | void __ref psci_cpu_die(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |        const struct psci_power_state ps = { | 
					
						
							|  |  |  |                .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, | 
					
						
							|  |  |  |        }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        if (psci_ops.cpu_off) | 
					
						
							|  |  |  |                psci_ops.cpu_off(ps); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        /* We should never return */ | 
					
						
							|  |  |  |        panic("psci: cpu %d failed to shutdown\n", cpu); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool __init psci_smp_available(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* is cpu_on available at least? */ | 
					
						
							|  |  |  | 	return (psci_ops.cpu_on != NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct smp_operations __initdata psci_smp_ops = { | 
					
						
							|  |  |  | 	.smp_boot_secondary	= psci_boot_secondary, | 
					
						
							| 
									
										
										
										
											2013-06-03 23:09:14 +01:00
										 |  |  | #ifdef CONFIG_HOTPLUG_CPU
 | 
					
						
							| 
									
										
										
										
											2013-05-21 14:24:11 +00:00
										 |  |  | 	.cpu_die		= psci_cpu_die, | 
					
						
							| 
									
										
										
										
											2013-06-03 23:09:14 +01:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-05-21 14:24:11 +00:00
										 |  |  | }; |