Merge branch 'fixes-base' into fixes
[sfrench/cifs-2.6.git] / arch / arm64 / kernel / cpu_ops.c
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 acpi_parking_protocol_ops;
29 extern const struct cpu_operations cpu_psci_ops;
30
31 const struct cpu_operations *cpu_ops[NR_CPUS];
32
33 static const struct cpu_operations *dt_supported_cpu_ops[] __initconst = {
34         &smp_spin_table_ops,
35         &cpu_psci_ops,
36         NULL,
37 };
38
39 static const struct cpu_operations *acpi_supported_cpu_ops[] __initconst = {
40 #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
41         &acpi_parking_protocol_ops,
42 #endif
43         &cpu_psci_ops,
44         NULL,
45 };
46
47 static const struct cpu_operations * __init cpu_get_ops(const char *name)
48 {
49         const struct cpu_operations **ops;
50
51         ops = acpi_disabled ? dt_supported_cpu_ops : acpi_supported_cpu_ops;
52
53         while (*ops) {
54                 if (!strcmp(name, (*ops)->name))
55                         return *ops;
56
57                 ops++;
58         }
59
60         return NULL;
61 }
62
63 static const char *__init cpu_read_enable_method(int cpu)
64 {
65         const char *enable_method;
66
67         if (acpi_disabled) {
68                 struct device_node *dn = of_get_cpu_node(cpu, NULL);
69
70                 if (!dn) {
71                         if (!cpu)
72                                 pr_err("Failed to find device node for boot cpu\n");
73                         return NULL;
74                 }
75
76                 enable_method = of_get_property(dn, "enable-method", NULL);
77                 if (!enable_method) {
78                         /*
79                          * The boot CPU may not have an enable method (e.g.
80                          * when spin-table is used for secondaries).
81                          * Don't warn spuriously.
82                          */
83                         if (cpu != 0)
84                                 pr_err("%s: missing enable-method property\n",
85                                         dn->full_name);
86                 }
87         } else {
88                 enable_method = acpi_get_enable_method(cpu);
89                 if (!enable_method) {
90                         /*
91                          * In ACPI systems the boot CPU does not require
92                          * checking the enable method since for some
93                          * boot protocol (ie parking protocol) it need not
94                          * be initialized. Don't warn spuriously.
95                          */
96                         if (cpu != 0)
97                                 pr_err("Unsupported ACPI enable-method\n");
98                 }
99         }
100
101         return enable_method;
102 }
103 /*
104  * Read a cpu's enable method and record it in cpu_ops.
105  */
106 int __init cpu_read_ops(int cpu)
107 {
108         const char *enable_method = cpu_read_enable_method(cpu);
109
110         if (!enable_method)
111                 return -ENODEV;
112
113         cpu_ops[cpu] = cpu_get_ops(enable_method);
114         if (!cpu_ops[cpu]) {
115                 pr_warn("Unsupported enable-method: %s\n", enable_method);
116                 return -EOPNOTSUPP;
117         }
118
119         return 0;
120 }