Commit | Line | Data |
---|---|---|
cd1aebf5 MR |
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> | |
e8765b26 MR |
20 | #include <asm/smp_plat.h> |
21 | #include <linux/errno.h> | |
22 | #include <linux/of.h> | |
cd1aebf5 MR |
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 | ||
e8765b26 | 38 | static const struct cpu_operations * __init cpu_get_ops(const char *name) |
cd1aebf5 MR |
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 | } | |
e8765b26 MR |
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]) { | |
264666e6 CM |
71 | pr_warn("%s: unsupported enable-method property: %s\n", |
72 | dn->full_name, enable_method); | |
e8765b26 MR |
73 | return -EOPNOTSUPP; |
74 | } | |
75 | ||
76 | return 0; | |
77 | } | |
78 | ||
79 | void __init cpu_read_bootcpu_ops(void) | |
80 | { | |
248f0e7f SK |
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; | |
e8765b26 | 85 | } |
248f0e7f | 86 | cpu_read_ops(dn, 0); |
e8765b26 | 87 | } |