1 /* 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License version 2 as 4 * published by the Free Software Foundation. 5 * 6 * This program is distributed in the hope that it will be useful, 7 * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 * GNU General Public License for more details. 10 * 11 * Copyright (C) 2012 ARM Limited 12 * 13 * Author: Will Deacon <will.deacon@arm.com> 14 */ 15 16 #include <linux/init.h> 17 #include <linux/smp.h> 18 #include <linux/of.h> 19 20 #include <asm/psci.h> 21 #include <asm/smp_plat.h> 22 23 /* 24 * psci_smp assumes that the following is true about PSCI: 25 * 26 * cpu_suspend Suspend the execution on a CPU 27 * @state we don't currently describe affinity levels, so just pass 0. 28 * @entry_point the first instruction to be executed on return 29 * returns 0 success, < 0 on failure 30 * 31 * cpu_off Power down a CPU 32 * @state we don't currently describe affinity levels, so just pass 0. 33 * no return on successful call 34 * 35 * cpu_on Power up a CPU 36 * @cpuid cpuid of target CPU, as from MPIDR 37 * @entry_point the first instruction to be executed on return 38 * returns 0 success, < 0 on failure 39 * 40 * migrate Migrate the context to a different CPU 41 * @cpuid cpuid of target CPU, as from MPIDR 42 * returns 0 success, < 0 on failure 43 * 44 */ 45 46 extern void secondary_startup(void); 47 48 static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) 49 { 50 if (psci_ops.cpu_on) 51 return psci_ops.cpu_on(cpu_logical_map(cpu), 52 __pa(secondary_startup)); 53 return -ENODEV; 54 } 55 56 #ifdef CONFIG_HOTPLUG_CPU 57 void __ref psci_cpu_die(unsigned int cpu) 58 { 59 const struct psci_power_state ps = { 60 .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, 61 }; 62 63 if (psci_ops.cpu_off) 64 psci_ops.cpu_off(ps); 65 66 /* We should never return */ 67 panic("psci: cpu %d failed to shutdown\n", cpu); 68 } 69 #endif 70 71 bool __init psci_smp_available(void) 72 { 73 /* is cpu_on available at least? */ 74 return (psci_ops.cpu_on != NULL); 75 } 76 77 struct smp_operations __initdata psci_smp_ops = { 78 .smp_boot_secondary = psci_boot_secondary, 79 #ifdef CONFIG_HOTPLUG_CPU 80 .cpu_die = psci_cpu_die, 81 #endif 82 }; 83