Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * CPU kernel entry/exit control
0004  *
0005  * Copyright (C) 2013 ARM Ltd.
0006  */
0007 
0008 #include <linux/acpi.h>
0009 #include <linux/cache.h>
0010 #include <linux/errno.h>
0011 #include <linux/of.h>
0012 #include <linux/string.h>
0013 #include <asm/acpi.h>
0014 #include <asm/cpu_ops.h>
0015 #include <asm/smp_plat.h>
0016 
0017 extern const struct cpu_operations smp_spin_table_ops;
0018 #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
0019 extern const struct cpu_operations acpi_parking_protocol_ops;
0020 #endif
0021 extern const struct cpu_operations cpu_psci_ops;
0022 
0023 static const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
0024 
0025 static const struct cpu_operations *const dt_supported_cpu_ops[] __initconst = {
0026     &smp_spin_table_ops,
0027     &cpu_psci_ops,
0028     NULL,
0029 };
0030 
0031 static const struct cpu_operations *const acpi_supported_cpu_ops[] __initconst = {
0032 #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
0033     &acpi_parking_protocol_ops,
0034 #endif
0035     &cpu_psci_ops,
0036     NULL,
0037 };
0038 
0039 static const struct cpu_operations * __init cpu_get_ops(const char *name)
0040 {
0041     const struct cpu_operations *const *ops;
0042 
0043     ops = acpi_disabled ? dt_supported_cpu_ops : acpi_supported_cpu_ops;
0044 
0045     while (*ops) {
0046         if (!strcmp(name, (*ops)->name))
0047             return *ops;
0048 
0049         ops++;
0050     }
0051 
0052     return NULL;
0053 }
0054 
0055 static const char *__init cpu_read_enable_method(int cpu)
0056 {
0057     const char *enable_method;
0058 
0059     if (acpi_disabled) {
0060         struct device_node *dn = of_get_cpu_node(cpu, NULL);
0061 
0062         if (!dn) {
0063             if (!cpu)
0064                 pr_err("Failed to find device node for boot cpu\n");
0065             return NULL;
0066         }
0067 
0068         enable_method = of_get_property(dn, "enable-method", NULL);
0069         if (!enable_method) {
0070             /*
0071              * The boot CPU may not have an enable method (e.g.
0072              * when spin-table is used for secondaries).
0073              * Don't warn spuriously.
0074              */
0075             if (cpu != 0)
0076                 pr_err("%pOF: missing enable-method property\n",
0077                     dn);
0078         }
0079         of_node_put(dn);
0080     } else {
0081         enable_method = acpi_get_enable_method(cpu);
0082         if (!enable_method) {
0083             /*
0084              * In ACPI systems the boot CPU does not require
0085              * checking the enable method since for some
0086              * boot protocol (ie parking protocol) it need not
0087              * be initialized. Don't warn spuriously.
0088              */
0089             if (cpu != 0)
0090                 pr_err("Unsupported ACPI enable-method\n");
0091         }
0092     }
0093 
0094     return enable_method;
0095 }
0096 /*
0097  * Read a cpu's enable method and record it in cpu_ops.
0098  */
0099 int __init init_cpu_ops(int cpu)
0100 {
0101     const char *enable_method = cpu_read_enable_method(cpu);
0102 
0103     if (!enable_method)
0104         return -ENODEV;
0105 
0106     cpu_ops[cpu] = cpu_get_ops(enable_method);
0107     if (!cpu_ops[cpu]) {
0108         pr_warn("Unsupported enable-method: %s\n", enable_method);
0109         return -EOPNOTSUPP;
0110     }
0111 
0112     return 0;
0113 }
0114 
0115 const struct cpu_operations *get_cpu_ops(int cpu)
0116 {
0117     return cpu_ops[cpu];
0118 }