aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/arm64/include/asm/cputype.h2
-rw-r--r--arch/arm64/include/asm/smp_plat.h30
-rw-r--r--arch/arm64/kernel/setup.c4
-rw-r--r--arch/arm64/kernel/smp.c92
4 files changed, 121 insertions, 7 deletions
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 9397a17bec0b..3780b2e7f88f 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -28,6 +28,8 @@
28 28
29#define INVALID_HWID ULONG_MAX 29#define INVALID_HWID ULONG_MAX
30 30
31#define MPIDR_HWID_BITMASK 0xff00ffffff
32
31#define read_cpuid(reg) ({ \ 33#define read_cpuid(reg) ({ \
32 u64 __val; \ 34 u64 __val; \
33 asm("mrs %0, " reg : "=r" (__val)); \ 35 asm("mrs %0, " reg : "=r" (__val)); \
diff --git a/arch/arm64/include/asm/smp_plat.h b/arch/arm64/include/asm/smp_plat.h
new file mode 100644
index 000000000000..ed43a0d2b1b2
--- /dev/null
+++ b/arch/arm64/include/asm/smp_plat.h
@@ -0,0 +1,30 @@
1/*
2 * Definitions specific to SMP platforms.
3 *
4 * Copyright (C) 2013 ARM Ltd.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __ASM_SMP_PLAT_H
20#define __ASM_SMP_PLAT_H
21
22#include <asm/types.h>
23
24/*
25 * Logical CPU mapping.
26 */
27extern u64 __cpu_logical_map[NR_CPUS];
28#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
29
30#endif /* __ASM_SMP_PLAT_H */
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 9c023d714f44..6a9a53292590 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -47,6 +47,7 @@
47#include <asm/cputable.h> 47#include <asm/cputable.h>
48#include <asm/sections.h> 48#include <asm/sections.h>
49#include <asm/setup.h> 49#include <asm/setup.h>
50#include <asm/smp_plat.h>
50#include <asm/cacheflush.h> 51#include <asm/cacheflush.h>
51#include <asm/tlbflush.h> 52#include <asm/tlbflush.h>
52#include <asm/traps.h> 53#include <asm/traps.h>
@@ -241,6 +242,8 @@ static void __init request_standard_resources(void)
241 } 242 }
242} 243}
243 244
245u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
246
244void __init setup_arch(char **cmdline_p) 247void __init setup_arch(char **cmdline_p)
245{ 248{
246 setup_processor(); 249 setup_processor();
@@ -265,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
265 268
266 psci_init(); 269 psci_init();
267 270
271 cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
268#ifdef CONFIG_SMP 272#ifdef CONFIG_SMP
269 smp_init_cpus(); 273 smp_init_cpus();
270#endif 274#endif
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)