1 /* 2 * CPU kernel entry/exit control 3 * 4 * Copyright (C) 2013 ARM Ltd. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <asm/cpu_ops.h> 20 #include <asm/smp_plat.h> 21 #include <linux/errno.h> 22 #include <linux/of.h> 23 #include <linux/string.h> 24 25 extern const struct cpu_operations smp_spin_table_ops; 26 extern const struct cpu_operations cpu_psci_ops; 27 28 const struct cpu_operations *cpu_ops[NR_CPUS]; 29 30 static const struct cpu_operations *supported_cpu_ops[] __initconst = { 31 #ifdef CONFIG_SMP 32 &smp_spin_table_ops, 33 &cpu_psci_ops, 34 #endif 35 NULL, 36 }; 37 38 static const struct cpu_operations * __init cpu_get_ops(const char *name) 39 { 40 const struct cpu_operations **ops = supported_cpu_ops; 41 42 while (*ops) { 43 if (!strcmp(name, (*ops)->name)) 44 return *ops; 45 46 ops++; 47 } 48 49 return NULL; 50 } 51 52 /* 53 * Read a cpu's enable method from the device tree and record it in cpu_ops. 54 */ 55 int __init cpu_read_ops(struct device_node *dn, int cpu) 56 { 57 const char *enable_method = of_get_property(dn, "enable-method", NULL); 58 if (!enable_method) { 59 /* 60 * The boot CPU may not have an enable method (e.g. when 61 * spin-table is used for secondaries). Don't warn spuriously. 62 */ 63 if (cpu != 0) 64 pr_err("%s: missing enable-method property\n", 65 dn->full_name); 66 return -ENOENT; 67 } 68 69 cpu_ops[cpu] = cpu_get_ops(enable_method); 70 if (!cpu_ops[cpu]) { 71 pr_warn("%s: unsupported enable-method property: %s\n", 72 dn->full_name, enable_method); 73 return -EOPNOTSUPP; 74 } 75 76 return 0; 77 } 78 79 void __init cpu_read_bootcpu_ops(void) 80 { 81 struct device_node *dn = of_get_cpu_node(0, NULL); 82 if (!dn) { 83 pr_err("Failed to find device node for boot cpu\n"); 84 return; 85 } 86 cpu_read_ops(dn, 0); 87 } 88