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 #ifdef CONFIG_SMP 34 &smp_spin_table_ops, 35 #endif 36 &cpu_psci_ops, 37 NULL, 38 }; 39 40 static const struct cpu_operations * __init cpu_get_ops(const char *name) 41 { 42 const struct cpu_operations **ops = supported_cpu_ops; 43 44 while (*ops) { 45 if (!strcmp(name, (*ops)->name)) 46 return *ops; 47 48 ops++; 49 } 50 51 return NULL; 52 } 53 54 static const char *__init cpu_read_enable_method(int cpu) 55 { 56 const char *enable_method; 57 58 if (acpi_disabled) { 59 struct device_node *dn = of_get_cpu_node(cpu, NULL); 60 61 if (!dn) { 62 if (!cpu) 63 pr_err("Failed to find device node for boot cpu\n"); 64 return NULL; 65 } 66 67 enable_method = of_get_property(dn, "enable-method", NULL); 68 if (!enable_method) { 69 /* 70 * The boot CPU may not have an enable method (e.g. 71 * when spin-table is used for secondaries). 72 * Don't warn spuriously. 73 */ 74 if (cpu != 0) 75 pr_err("%s: missing enable-method property\n", 76 dn->full_name); 77 } 78 } else { 79 enable_method = acpi_get_enable_method(cpu); 80 if (!enable_method) 81 pr_err("Unsupported ACPI enable-method\n"); 82 } 83 84 return enable_method; 85 } 86 /* 87 * Read a cpu's enable method and record it in cpu_ops. 88 */ 89 int __init cpu_read_ops(int cpu) 90 { 91 const char *enable_method = cpu_read_enable_method(cpu); 92 93 if (!enable_method) 94 return -ENODEV; 95 96 cpu_ops[cpu] = cpu_get_ops(enable_method); 97 if (!cpu_ops[cpu]) { 98 pr_warn("Unsupported enable-method: %s\n", enable_method); 99 return -EOPNOTSUPP; 100 } 101 102 return 0; 103 } 104