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