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 27extern const struct cpu_operations smp_spin_table_ops; 28extern const struct cpu_operations cpu_psci_ops; 29 30const struct cpu_operations *cpu_ops[NR_CPUS]; 31 32static const struct cpu_operations *supported_cpu_ops[] __initconst = { 33 &smp_spin_table_ops, 34 &cpu_psci_ops, 35 NULL, 36}; 37 38static 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 52static 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 */ 87int __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