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 <linux/acpi.h> 20 #include <linux/errno.h> 21 #include <linux/of.h> 22 #include <linux/string.h> 23 #include <asm/acpi.h> 24 #include <asm/cpu_ops.h> 25 #include <asm/smp_plat.h> 26 27 extern const struct cpu_operations smp_spin_table_ops; 28 extern const struct cpu_operations cpu_psci_ops; 29 30 const struct cpu_operations *cpu_ops[NR_CPUS]; 31 32 static const struct cpu_operations *supported_cpu_ops[] __initconst = { 33 &smp_spin_table_ops, 34 &cpu_psci_ops, 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 static const char *__init cpu_read_enable_method(int cpu) 53 { 54 const char *enable_method; 55 56 if (acpi_disabled) { 57 struct device_node *dn = of_get_cpu_node(cpu, NULL); 58 59 if (!dn) { 60 if (!cpu) 61 pr_err("Failed to find device node for boot cpu\n"); 62 return NULL; 63 } 64 65 enable_method = of_get_property(dn, "enable-method", NULL); 66 if (!enable_method) { 67 /* 68 * The boot CPU may not have an enable method (e.g. 69 * when spin-table is used for secondaries). 70 * Don't warn spuriously. 71 */ 72 if (cpu != 0) 73 pr_err("%s: missing enable-method property\n", 74 dn->full_name); 75 } 76 } else { 77 enable_method = acpi_get_enable_method(cpu); 78 if (!enable_method) 79 pr_err("Unsupported ACPI enable-method\n"); 80 } 81 82 return enable_method; 83 } 84 /* 85 * Read a cpu's enable method and record it in cpu_ops. 86 */ 87 int __init cpu_read_ops(int cpu) 88 { 89 const char *enable_method = cpu_read_enable_method(cpu); 90 91 if (!enable_method) 92 return -ENODEV; 93 94 cpu_ops[cpu] = cpu_get_ops(enable_method); 95 if (!cpu_ops[cpu]) { 96 pr_warn("Unsupported enable-method: %s\n", enable_method); 97 return -EOPNOTSUPP; 98 } 99 100 return 0; 101 } 102