diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2013-01-02 15:24:22 +0000 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2013-01-29 16:56:37 +0000 |
commit | d329de3f2ada413c7cd16e1dc1d70d4abc7309e9 (patch) | |
tree | ae7880c26aa4bc2ac1ac5b3b983e992638e49f67 /arch/arm64/kernel/smp.c | |
parent | 75e424620a4f8247e8877c224d0457efadf88201 (diff) | |
download | lwn-d329de3f2ada413c7cd16e1dc1d70d4abc7309e9.tar.gz lwn-d329de3f2ada413c7cd16e1dc1d70d4abc7309e9.zip |
arm64: SMP: rework the SMP code to be enabling method agnostic
In order to introduce PSCI support, let the SMP code handle
multiple enabling methods. This also allow CPUs to be booted
using different methods (though this feels a bit weird...).
In the process, move the spin-table code to its own file.
Signed-off-by: Marc Zyngier <marc.zyngier@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.c | 68 |
1 files changed, 46 insertions, 22 deletions
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 538300f2273d..7776922945af 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -233,7 +233,27 @@ void __init smp_prepare_boot_cpu(void) } static void (*smp_cross_call)(const struct cpumask *, unsigned int); -static phys_addr_t cpu_release_addr[NR_CPUS]; + +static const struct smp_enable_ops *enable_ops[] __initconst = { + &smp_spin_table_ops, + NULL, +}; + +static const struct smp_enable_ops *smp_enable_ops[NR_CPUS]; + +static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name) +{ + const struct smp_enable_ops *ops = enable_ops[0]; + + while (ops) { + if (!strcmp(name, ops->name)) + return ops; + + ops++; + } + + return NULL; +} /* * Enumerate the possible CPU set from the device tree. @@ -252,22 +272,22 @@ void __init smp_init_cpus(void) * We currently support only the "spin-table" enable-method. */ enable_method = of_get_property(dn, "enable-method", NULL); - if (!enable_method || strcmp(enable_method, "spin-table")) { - pr_err("CPU %d: missing or invalid enable-method property: %s\n", - cpu, enable_method); + if (!enable_method) { + pr_err("CPU %d: missing enable-method property\n", cpu); goto next; } - /* - * Determine the address from which the CPU is polling. - */ - if (of_property_read_u64(dn, "cpu-release-addr", - &cpu_release_addr[cpu])) { - pr_err("CPU %d: missing or invalid cpu-release-addr property\n", - cpu); + smp_enable_ops[cpu] = smp_get_enable_ops(enable_method); + + if (!smp_enable_ops[cpu]) { + pr_err("CPU %d: invalid enable-method property: %s\n", + cpu, enable_method); goto next; } + if (smp_enable_ops[cpu]->init_cpu(dn, cpu)) + goto next; + set_cpu_possible(cpu, true); next: cpu++; @@ -281,8 +301,7 @@ next: void __init smp_prepare_cpus(unsigned int max_cpus) { - int cpu; - void **release_addr; + int cpu, err; unsigned int ncores = num_possible_cpus(); /* @@ -291,30 +310,35 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (max_cpus > ncores) max_cpus = ncores; + /* Don't bother if we're effectively UP */ + if (max_cpus <= 1) + return; + /* * Initialise the present map (which describes the set of CPUs * actually populated at the present time) and release the * secondaries from the bootloader. + * + * Make sure we online at most (max_cpus - 1) additional CPUs. */ + max_cpus--; for_each_possible_cpu(cpu) { if (max_cpus == 0) break; - if (!cpu_release_addr[cpu]) + if (cpu == smp_processor_id()) + continue; + + if (!smp_enable_ops[cpu]) continue; - release_addr = __va(cpu_release_addr[cpu]); - release_addr[0] = (void *)__pa(secondary_holding_pen); - __flush_dcache_area(release_addr, sizeof(release_addr[0])); + err = smp_enable_ops[cpu]->prepare_cpu(cpu); + if (err) + continue; set_cpu_present(cpu, true); max_cpus--; } - - /* - * Send an event to wake up the secondaries. - */ - sev(); } |