aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/smp.c
diff options
context:
space:
mode:
authorJavi Merino <javi.merino@arm.com>2012-08-29 04:47:19 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2013-03-20 13:26:24 -0400
commit4c7aa0021356ee91b96cea51b8b7fadebaba489e (patch)
tree2af7dd584c30a3ce79cc912a4873bd743c6d08ca /arch/arm64/kernel/smp.c
parent3e98fdacc59bbbdbb659be1a144ccc48ed4860fa (diff)
arm64: kernel: initialise cpu_logical_map from the DT
When booting the kernel, the cpu logical id map must be initialised using device tree data passed by FW or through an embedded blob. This patch parses the reg property in device tree "cpu" nodes, retrieves the corresponding CPUs hardware identifiers (MPIDR) and initialises the cpu logical map accordingly. The device tree HW identifiers are considered valid if all CPU nodes contain a "reg" property, there are no duplicate "reg" entries and the DT defines a CPU node whose "reg" property defines affinity levels that matches those of the boot CPU. The primary CPU is assigned cpu logical number 0 to keep the current convention valid. Based on a0ae02405076ac32bd17ece976e914b5b6075bb0 (ARM: kernel: add device tree init map function). Signed-off-by: Javi Merino <javi.merino@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/kernel/smp.c')
-rw-r--r--arch/arm64/kernel/smp.c92
1 files changed, 85 insertions, 7 deletions
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index a57a373d305f..d4dcc6515253 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -43,6 +43,7 @@
43#include <asm/pgtable.h> 43#include <asm/pgtable.h>
44#include <asm/pgalloc.h> 44#include <asm/pgalloc.h>
45#include <asm/processor.h> 45#include <asm/processor.h>
46#include <asm/smp_plat.h>
46#include <asm/sections.h> 47#include <asm/sections.h>
47#include <asm/tlbflush.h> 48#include <asm/tlbflush.h>
48#include <asm/ptrace.h> 49#include <asm/ptrace.h>
@@ -96,7 +97,7 @@ static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
96 /* 97 /*
97 * Update the pen release flag. 98 * Update the pen release flag.
98 */ 99 */
99 write_pen_release(cpu); 100 write_pen_release(cpu_logical_map(cpu));
100 101
101 /* 102 /*
102 * Send an event, causing the secondaries to read pen_release. 103 * Send an event, causing the secondaries to read pen_release.
@@ -257,15 +258,77 @@ static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
257} 258}
258 259
259/* 260/*
260 * Enumerate the possible CPU set from the device tree. 261 * Enumerate the possible CPU set from the device tree and build the
262 * cpu logical map array containing MPIDR values related to logical
263 * cpus. Assumes that cpu_logical_map(0) has already been initialized.
261 */ 264 */
262void __init smp_init_cpus(void) 265void __init smp_init_cpus(void)
263{ 266{
264 const char *enable_method; 267 const char *enable_method;
265 struct device_node *dn = NULL; 268 struct device_node *dn = NULL;
266 int cpu = 0; 269 int i, cpu = 1;
270 bool bootcpu_valid = false;
267 271
268 while ((dn = of_find_node_by_type(dn, "cpu"))) { 272 while ((dn = of_find_node_by_type(dn, "cpu"))) {
273 u64 hwid;
274
275 /*
276 * A cpu node with missing "reg" property is
277 * considered invalid to build a cpu_logical_map
278 * entry.
279 */
280 if (of_property_read_u64(dn, "reg", &hwid)) {
281 pr_err("%s: missing reg property\n", dn->full_name);
282 goto next;
283 }
284
285 /*
286 * Non affinity bits must be set to 0 in the DT
287 */
288 if (hwid & ~MPIDR_HWID_BITMASK) {
289 pr_err("%s: invalid reg property\n", dn->full_name);
290 goto next;
291 }
292
293 /*
294 * Duplicate MPIDRs are a recipe for disaster. Scan
295 * all initialized entries and check for
296 * duplicates. If any is found just ignore the cpu.
297 * cpu_logical_map was initialized to INVALID_HWID to
298 * avoid matching valid MPIDR values.
299 */
300 for (i = 1; (i < cpu) && (i < NR_CPUS); i++) {
301 if (cpu_logical_map(i) == hwid) {
302 pr_err("%s: duplicate cpu reg properties in the DT\n",
303 dn->full_name);
304 goto next;
305 }
306 }
307
308 /*
309 * The numbering scheme requires that the boot CPU
310 * must be assigned logical id 0. Record it so that
311 * the logical map built from DT is validated and can
312 * be used.
313 */
314 if (hwid == cpu_logical_map(0)) {
315 if (bootcpu_valid) {
316 pr_err("%s: duplicate boot cpu reg property in DT\n",
317 dn->full_name);
318 goto next;
319 }
320
321 bootcpu_valid = true;
322
323 /*
324 * cpu_logical_map has already been
325 * initialized and the boot cpu doesn't need
326 * the enable-method so continue without
327 * incrementing cpu.
328 */
329 continue;
330 }
331
269 if (cpu >= NR_CPUS) 332 if (cpu >= NR_CPUS)
270 goto next; 333 goto next;
271 334
@@ -274,22 +337,24 @@ void __init smp_init_cpus(void)
274 */ 337 */
275 enable_method = of_get_property(dn, "enable-method", NULL); 338 enable_method = of_get_property(dn, "enable-method", NULL);
276 if (!enable_method) { 339 if (!enable_method) {
277 pr_err("CPU %d: missing enable-method property\n", cpu); 340 pr_err("%s: missing enable-method property\n",
341 dn->full_name);
278 goto next; 342 goto next;
279 } 343 }
280 344
281 smp_enable_ops[cpu] = smp_get_enable_ops(enable_method); 345 smp_enable_ops[cpu] = smp_get_enable_ops(enable_method);
282 346
283 if (!smp_enable_ops[cpu]) { 347 if (!smp_enable_ops[cpu]) {
284 pr_err("CPU %d: invalid enable-method property: %s\n", 348 pr_err("%s: invalid enable-method property: %s\n",
285 cpu, enable_method); 349 dn->full_name, enable_method);
286 goto next; 350 goto next;
287 } 351 }
288 352
289 if (smp_enable_ops[cpu]->init_cpu(dn, cpu)) 353 if (smp_enable_ops[cpu]->init_cpu(dn, cpu))
290 goto next; 354 goto next;
291 355
292 set_cpu_possible(cpu, true); 356 pr_debug("cpu logical map 0x%llx\n", hwid);
357 cpu_logical_map(cpu) = hwid;
293next: 358next:
294 cpu++; 359 cpu++;
295 } 360 }
@@ -298,6 +363,19 @@ next:
298 if (cpu > NR_CPUS) 363 if (cpu > NR_CPUS)
299 pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n", 364 pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n",
300 cpu, NR_CPUS); 365 cpu, NR_CPUS);
366
367 if (!bootcpu_valid) {
368 pr_err("DT missing boot CPU MPIDR, not enabling secondaries\n");
369 return;
370 }
371
372 /*
373 * All the cpus that made it to the cpu_logical_map have been
374 * validated so set them as possible cpus.
375 */
376 for (i = 0; i < NR_CPUS; i++)
377 if (cpu_logical_map(i) != INVALID_HWID)
378 set_cpu_possible(i, true);
301} 379}
302 380
303void __init smp_prepare_cpus(unsigned int max_cpus) 381void __init smp_prepare_cpus(unsigned int max_cpus)