aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHanjun Guo <hanjun.guo@linaro.org>2015-03-24 10:02:45 -0400
committerWill Deacon <will.deacon@arm.com>2015-03-25 07:52:42 -0400
commitfccb9a81fd08b61bed91ddef88341694f8ecbfd1 (patch)
tree23bc0d3408923674d343960a8a80153a34da08eb
parent4c1c8d7a7ebc8b909493a14b21b233e5377b69aa (diff)
ARM64 / ACPI: Parse MADT for SMP initialization
MADT contains the information for MPIDR which is essential for SMP initialization, parse the GIC cpu interface structures to get the MPIDR value and map it to cpu_logical_map(), and add enabled cpu with valid MPIDR into cpu_possible_map. ACPI 5.1 only has two explicit methods to boot up SMP, PSCI and Parking protocol, but the Parking protocol is only specified for ARMv7 now, so make PSCI as the only way for the SMP boot protocol before some updates for the ACPI spec or the Parking protocol spec. Parking protocol patches for SMP boot will be sent to upstream when the new version of Parking protocol is ready. CC: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> CC: Catalin Marinas <catalin.marinas@arm.com> CC: Will Deacon <will.deacon@arm.com> CC: Mark Rutland <mark.rutland@arm.com> Tested-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> Tested-by: Yijing Wang <wangyijing@huawei.com> Tested-by: Mark Langsdorf <mlangsdo@redhat.com> Tested-by: Jon Masters <jcm@redhat.com> Tested-by: Timur Tabi <timur@codeaurora.org> Tested-by: Robert Richter <rrichter@cavium.com> Acked-by: Robert Richter <rrichter@cavium.com> Acked-by: Olof Johansson <olof@lixom.net> Reviewed-by: Grant Likely <grant.likely@linaro.org> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org> Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/include/asm/acpi.h2
-rw-r--r--arch/arm64/include/asm/cpu_ops.h1
-rw-r--r--arch/arm64/include/asm/smp.h5
-rw-r--r--arch/arm64/kernel/acpi.c149
-rw-r--r--arch/arm64/kernel/cpu_ops.c2
-rw-r--r--arch/arm64/kernel/setup.c7
-rw-r--r--arch/arm64/kernel/smp.c2
7 files changed, 160 insertions, 8 deletions
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 9ea650c991c9..9719921aedb1 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -71,10 +71,12 @@ static inline bool acpi_has_cpu_in_madt(void)
71} 71}
72 72
73static inline void arch_fix_phys_package_id(int num, u32 slot) { } 73static inline void arch_fix_phys_package_id(int num, u32 slot) { }
74void __init acpi_init_cpus(void);
74 75
75#else 76#else
76static inline bool acpi_psci_present(void) { return false; } 77static inline bool acpi_psci_present(void) { return false; }
77static inline bool acpi_psci_use_hvc(void) { return false; } 78static inline bool acpi_psci_use_hvc(void) { return false; }
79static inline void acpi_init_cpus(void) { }
78#endif /* CONFIG_ACPI */ 80#endif /* CONFIG_ACPI */
79 81
80#endif /*_ASM_ACPI_H*/ 82#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h
index da301ee7395c..5a31d6716914 100644
--- a/arch/arm64/include/asm/cpu_ops.h
+++ b/arch/arm64/include/asm/cpu_ops.h
@@ -66,5 +66,6 @@ struct cpu_operations {
66extern const struct cpu_operations *cpu_ops[NR_CPUS]; 66extern const struct cpu_operations *cpu_ops[NR_CPUS];
67int __init cpu_read_ops(struct device_node *dn, int cpu); 67int __init cpu_read_ops(struct device_node *dn, int cpu);
68void __init cpu_read_bootcpu_ops(void); 68void __init cpu_read_bootcpu_ops(void);
69const struct cpu_operations *cpu_get_ops(const char *name);
69 70
70#endif /* ifndef __ASM_CPU_OPS_H */ 71#endif /* ifndef __ASM_CPU_OPS_H */
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 780f82c827b6..bf22650b1a78 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -39,9 +39,10 @@ extern void show_ipi_list(struct seq_file *p, int prec);
39extern void handle_IPI(int ipinr, struct pt_regs *regs); 39extern void handle_IPI(int ipinr, struct pt_regs *regs);
40 40
41/* 41/*
42 * Setup the set of possible CPUs (via set_cpu_possible) 42 * Discover the set of possible CPUs and determine their
43 * SMP operations.
43 */ 44 */
44extern void smp_init_cpus(void); 45extern void of_smp_init_cpus(void);
45 46
46/* 47/*
47 * Provide a function to raise an IPI cross call on CPUs in callmap. 48 * Provide a function to raise an IPI cross call on CPUs in callmap.
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 2269e3032c07..c9203c0a1179 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -25,6 +25,10 @@
25#include <linux/of_fdt.h> 25#include <linux/of_fdt.h>
26#include <linux/smp.h> 26#include <linux/smp.h>
27 27
28#include <asm/cputype.h>
29#include <asm/cpu_ops.h>
30#include <asm/smp_plat.h>
31
28int acpi_noirq = 1; /* skip ACPI IRQ initialization */ 32int acpi_noirq = 1; /* skip ACPI IRQ initialization */
29int acpi_disabled = 1; 33int acpi_disabled = 1;
30EXPORT_SYMBOL(acpi_disabled); 34EXPORT_SYMBOL(acpi_disabled);
@@ -32,6 +36,12 @@ EXPORT_SYMBOL(acpi_disabled);
32int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */ 36int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */
33EXPORT_SYMBOL(acpi_pci_disabled); 37EXPORT_SYMBOL(acpi_pci_disabled);
34 38
39/* Processors with enabled flag and sane MPIDR */
40static int enabled_cpus;
41
42/* Boot CPU is valid or not in MADT */
43static bool bootcpu_valid __initdata;
44
35static bool param_acpi_off __initdata; 45static bool param_acpi_off __initdata;
36static bool param_acpi_force __initdata; 46static bool param_acpi_force __initdata;
37 47
@@ -85,6 +95,129 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
85 early_memunmap(map, size); 95 early_memunmap(map, size);
86} 96}
87 97
98/**
99 * acpi_map_gic_cpu_interface - generates a logical cpu number
100 * and map to MPIDR represented by GICC structure
101 * @mpidr: CPU's hardware id to register, MPIDR represented in MADT
102 * @enabled: this cpu is enabled or not
103 *
104 * Returns the logical cpu number which maps to MPIDR
105 */
106static int __init acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled)
107{
108 int i;
109
110 if (mpidr == INVALID_HWID) {
111 pr_info("Skip MADT cpu entry with invalid MPIDR\n");
112 return -EINVAL;
113 }
114
115 total_cpus++;
116 if (!enabled)
117 return -EINVAL;
118
119 if (enabled_cpus >= NR_CPUS) {
120 pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n",
121 NR_CPUS, total_cpus, mpidr);
122 return -EINVAL;
123 }
124
125 /* Check if GICC structure of boot CPU is available in the MADT */
126 if (cpu_logical_map(0) == mpidr) {
127 if (bootcpu_valid) {
128 pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
129 mpidr);
130 return -EINVAL;
131 }
132
133 bootcpu_valid = true;
134 }
135
136 /*
137 * Duplicate MPIDRs are a recipe for disaster. Scan
138 * all initialized entries and check for
139 * duplicates. If any is found just ignore the CPU.
140 */
141 for (i = 1; i < enabled_cpus; i++) {
142 if (cpu_logical_map(i) == mpidr) {
143 pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
144 mpidr);
145 return -EINVAL;
146 }
147 }
148
149 if (!acpi_psci_present())
150 return -EOPNOTSUPP;
151
152 cpu_ops[enabled_cpus] = cpu_get_ops("psci");
153 /* CPU 0 was already initialized */
154 if (enabled_cpus) {
155 if (!cpu_ops[enabled_cpus])
156 return -EINVAL;
157
158 if (cpu_ops[enabled_cpus]->cpu_init(NULL, enabled_cpus))
159 return -EOPNOTSUPP;
160
161 /* map the logical cpu id to cpu MPIDR */
162 cpu_logical_map(enabled_cpus) = mpidr;
163 }
164
165 enabled_cpus++;
166 return enabled_cpus;
167}
168
169static int __init
170acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
171 const unsigned long end)
172{
173 struct acpi_madt_generic_interrupt *processor;
174
175 processor = (struct acpi_madt_generic_interrupt *)header;
176
177 if (BAD_MADT_ENTRY(processor, end))
178 return -EINVAL;
179
180 acpi_table_print_madt_entry(header);
181
182 acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK,
183 processor->flags & ACPI_MADT_ENABLED);
184
185 return 0;
186}
187
188/* Parse GIC cpu interface entries in MADT for SMP init */
189void __init acpi_init_cpus(void)
190{
191 int count, i;
192
193 /*
194 * do a partial walk of MADT to determine how many CPUs
195 * we have including disabled CPUs, and get information
196 * we need for SMP init
197 */
198 count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
199 acpi_parse_gic_cpu_interface, 0);
200
201 if (!count) {
202 pr_err("No GIC CPU interface entries present\n");
203 return;
204 } else if (count < 0) {
205 pr_err("Error parsing GIC CPU interface entry\n");
206 return;
207 }
208
209 if (!bootcpu_valid) {
210 pr_err("MADT missing boot CPU MPIDR, not enabling secondaries\n");
211 return;
212 }
213
214 for (i = 0; i < enabled_cpus; i++)
215 set_cpu_possible(i, true);
216
217 /* Make boot-up look pretty */
218 pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus);
219}
220
88static int __init acpi_parse_fadt(struct acpi_table_header *table) 221static int __init acpi_parse_fadt(struct acpi_table_header *table)
89{ 222{
90 struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; 223 struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
@@ -96,8 +229,20 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
96 * boot protocol configuration data, or we will disable ACPI. 229 * boot protocol configuration data, or we will disable ACPI.
97 */ 230 */
98 if (table->revision > 5 || 231 if (table->revision > 5 ||
99 (table->revision == 5 && fadt->minor_revision >= 1)) 232 (table->revision == 5 && fadt->minor_revision >= 1)) {
100 return 0; 233 /*
234 * ACPI 5.1 only has two explicit methods to boot up SMP,
235 * PSCI and Parking protocol, but the Parking protocol is
236 * only specified for ARMv7 now, so make PSCI as the only
237 * way for the SMP boot protocol before some updates for
238 * the Parking protocol spec.
239 */
240 if (acpi_psci_present())
241 return 0;
242
243 pr_warn("No PSCI support, will not bring up secondary CPUs\n");
244 return -EOPNOTSUPP;
245 }
101 246
102 pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n", 247 pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
103 table->revision, fadt->minor_revision); 248 table->revision, fadt->minor_revision);
diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c
index cce952440c64..fb8ff9ba467a 100644
--- a/arch/arm64/kernel/cpu_ops.c
+++ b/arch/arm64/kernel/cpu_ops.c
@@ -35,7 +35,7 @@ static const struct cpu_operations *supported_cpu_ops[] __initconst = {
35 NULL, 35 NULL,
36}; 36};
37 37
38static const struct cpu_operations * __init cpu_get_ops(const char *name) 38const struct cpu_operations * __init cpu_get_ops(const char *name)
39{ 39{
40 const struct cpu_operations **ops = supported_cpu_ops; 40 const struct cpu_operations **ops = supported_cpu_ops;
41 41
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 97fa7f31981d..b2783111fd52 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -393,13 +393,16 @@ void __init setup_arch(char **cmdline_p)
393 if (acpi_disabled) { 393 if (acpi_disabled) {
394 unflatten_device_tree(); 394 unflatten_device_tree();
395 psci_dt_init(); 395 psci_dt_init();
396 cpu_read_bootcpu_ops();
397#ifdef CONFIG_SMP
398 of_smp_init_cpus();
399#endif
396 } else { 400 } else {
397 psci_acpi_init(); 401 psci_acpi_init();
402 acpi_init_cpus();
398 } 403 }
399 404
400 cpu_read_bootcpu_ops();
401#ifdef CONFIG_SMP 405#ifdef CONFIG_SMP
402 smp_init_cpus();
403 smp_build_mpidr_hash(); 406 smp_build_mpidr_hash();
404#endif 407#endif
405 408
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 328b8ce4b007..52998b7a89b5 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -322,7 +322,7 @@ void __init smp_prepare_boot_cpu(void)
322 * cpu logical map array containing MPIDR values related to logical 322 * cpu logical map array containing MPIDR values related to logical
323 * cpus. Assumes that cpu_logical_map(0) has already been initialized. 323 * cpus. Assumes that cpu_logical_map(0) has already been initialized.
324 */ 324 */
325void __init smp_init_cpus(void) 325void __init of_smp_init_cpus(void)
326{ 326{
327 struct device_node *dn = NULL; 327 struct device_node *dn = NULL;
328 unsigned int i, cpu = 1; 328 unsigned int i, cpu = 1;