Merge tag 'filelock-v5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton...
[linux-2.6-microblaze.git] / arch / arm64 / kernel / cpu_ops.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * CPU kernel entry/exit control
4  *
5  * Copyright (C) 2013 ARM Ltd.
6  */
7
8 #include <linux/acpi.h>
9 #include <linux/cache.h>
10 #include <linux/errno.h>
11 #include <linux/of.h>
12 #include <linux/string.h>
13 #include <asm/acpi.h>
14 #include <asm/cpu_ops.h>
15 #include <asm/smp_plat.h>
16
17 extern const struct cpu_operations smp_spin_table_ops;
18 #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
19 extern const struct cpu_operations acpi_parking_protocol_ops;
20 #endif
21 extern const struct cpu_operations cpu_psci_ops;
22
23 static const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
24
25 static const struct cpu_operations *const dt_supported_cpu_ops[] __initconst = {
26         &smp_spin_table_ops,
27         &cpu_psci_ops,
28         NULL,
29 };
30
31 static const struct cpu_operations *const acpi_supported_cpu_ops[] __initconst = {
32 #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
33         &acpi_parking_protocol_ops,
34 #endif
35         &cpu_psci_ops,
36         NULL,
37 };
38
39 static const struct cpu_operations * __init cpu_get_ops(const char *name)
40 {
41         const struct cpu_operations *const *ops;
42
43         ops = acpi_disabled ? dt_supported_cpu_ops : acpi_supported_cpu_ops;
44
45         while (*ops) {
46                 if (!strcmp(name, (*ops)->name))
47                         return *ops;
48
49                 ops++;
50         }
51
52         return NULL;
53 }
54
55 static const char *__init cpu_read_enable_method(int cpu)
56 {
57         const char *enable_method;
58
59         if (acpi_disabled) {
60                 struct device_node *dn = of_get_cpu_node(cpu, NULL);
61
62                 if (!dn) {
63                         if (!cpu)
64                                 pr_err("Failed to find device node for boot cpu\n");
65                         return NULL;
66                 }
67
68                 enable_method = of_get_property(dn, "enable-method", NULL);
69                 if (!enable_method) {
70                         /*
71                          * The boot CPU may not have an enable method (e.g.
72                          * when spin-table is used for secondaries).
73                          * Don't warn spuriously.
74                          */
75                         if (cpu != 0)
76                                 pr_err("%pOF: missing enable-method property\n",
77                                         dn);
78                 }
79                 of_node_put(dn);
80         } else {
81                 enable_method = acpi_get_enable_method(cpu);
82                 if (!enable_method) {
83                         /*
84                          * In ACPI systems the boot CPU does not require
85                          * checking the enable method since for some
86                          * boot protocol (ie parking protocol) it need not
87                          * be initialized. Don't warn spuriously.
88                          */
89                         if (cpu != 0)
90                                 pr_err("Unsupported ACPI enable-method\n");
91                 }
92         }
93
94         return enable_method;
95 }
96 /*
97  * Read a cpu's enable method and record it in cpu_ops.
98  */
99 int __init init_cpu_ops(int cpu)
100 {
101         const char *enable_method = cpu_read_enable_method(cpu);
102
103         if (!enable_method)
104                 return -ENODEV;
105
106         cpu_ops[cpu] = cpu_get_ops(enable_method);
107         if (!cpu_ops[cpu]) {
108                 pr_warn("Unsupported enable-method: %s\n", enable_method);
109                 return -EOPNOTSUPP;
110         }
111
112         return 0;
113 }
114
115 const struct cpu_operations *get_cpu_ops(int cpu)
116 {
117         return cpu_ops[cpu];
118 }