diff options
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) | |||
233 | } | 233 | } |
234 | 234 | ||
235 | static void (*smp_cross_call)(const struct cpumask *, unsigned int); | 235 | static void (*smp_cross_call)(const struct cpumask *, unsigned int); |
236 | static phys_addr_t cpu_release_addr[NR_CPUS]; | 236 | |
237 | static const struct smp_enable_ops *enable_ops[] __initconst = { | ||
238 | &smp_spin_table_ops, | ||
239 | NULL, | ||
240 | }; | ||
241 | |||
242 | static const struct smp_enable_ops *smp_enable_ops[NR_CPUS]; | ||
243 | |||
244 | static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name) | ||
245 | { | ||
246 | const struct smp_enable_ops *ops = enable_ops[0]; | ||
247 | |||
248 | while (ops) { | ||
249 | if (!strcmp(name, ops->name)) | ||
250 | return ops; | ||
251 | |||
252 | ops++; | ||
253 | } | ||
254 | |||
255 | return NULL; | ||
256 | } | ||
237 | 257 | ||
238 | /* | 258 | /* |
239 | * Enumerate the possible CPU set from the device tree. | 259 | * Enumerate the possible CPU set from the device tree. |
@@ -252,22 +272,22 @@ void __init smp_init_cpus(void) | |||
252 | * We currently support only the "spin-table" enable-method. | 272 | * We currently support only the "spin-table" enable-method. |
253 | */ | 273 | */ |
254 | enable_method = of_get_property(dn, "enable-method", NULL); | 274 | enable_method = of_get_property(dn, "enable-method", NULL); |
255 | if (!enable_method || strcmp(enable_method, "spin-table")) { | 275 | if (!enable_method) { |
256 | pr_err("CPU %d: missing or invalid enable-method property: %s\n", | 276 | pr_err("CPU %d: missing enable-method property\n", cpu); |
257 | cpu, enable_method); | ||
258 | goto next; | 277 | goto next; |
259 | } | 278 | } |
260 | 279 | ||
261 | /* | 280 | smp_enable_ops[cpu] = smp_get_enable_ops(enable_method); |
262 | * Determine the address from which the CPU is polling. | 281 | |
263 | */ | 282 | if (!smp_enable_ops[cpu]) { |
264 | if (of_property_read_u64(dn, "cpu-release-addr", | 283 | pr_err("CPU %d: invalid enable-method property: %s\n", |
265 | &cpu_release_addr[cpu])) { | 284 | cpu, enable_method); |
266 | pr_err("CPU %d: missing or invalid cpu-release-addr property\n", | ||
267 | cpu); | ||
268 | goto next; | 285 | goto next; |
269 | } | 286 | } |
270 | 287 | ||
288 | if (smp_enable_ops[cpu]->init_cpu(dn, cpu)) | ||
289 | goto next; | ||
290 | |||
271 | set_cpu_possible(cpu, true); | 291 | set_cpu_possible(cpu, true); |
272 | next: | 292 | next: |
273 | cpu++; | 293 | cpu++; |
@@ -281,8 +301,7 @@ next: | |||
281 | 301 | ||
282 | void __init smp_prepare_cpus(unsigned int max_cpus) | 302 | void __init smp_prepare_cpus(unsigned int max_cpus) |
283 | { | 303 | { |
284 | int cpu; | 304 | int cpu, err; |
285 | void **release_addr; | ||
286 | unsigned int ncores = num_possible_cpus(); | 305 | unsigned int ncores = num_possible_cpus(); |
287 | 306 | ||
288 | /* | 307 | /* |
@@ -291,30 +310,35 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
291 | if (max_cpus > ncores) | 310 | if (max_cpus > ncores) |
292 | max_cpus = ncores; | 311 | max_cpus = ncores; |
293 | 312 | ||
313 | /* Don't bother if we're effectively UP */ | ||
314 | if (max_cpus <= 1) | ||
315 | return; | ||
316 | |||
294 | /* | 317 | /* |
295 | * Initialise the present map (which describes the set of CPUs | 318 | * Initialise the present map (which describes the set of CPUs |
296 | * actually populated at the present time) and release the | 319 | * actually populated at the present time) and release the |
297 | * secondaries from the bootloader. | 320 | * secondaries from the bootloader. |
321 | * | ||
322 | * Make sure we online at most (max_cpus - 1) additional CPUs. | ||
298 | */ | 323 | */ |
324 | max_cpus--; | ||
299 | for_each_possible_cpu(cpu) { | 325 | for_each_possible_cpu(cpu) { |
300 | if (max_cpus == 0) | 326 | if (max_cpus == 0) |
301 | break; | 327 | break; |
302 | 328 | ||
303 | if (!cpu_release_addr[cpu]) | 329 | if (cpu == smp_processor_id()) |
330 | continue; | ||
331 | |||
332 | if (!smp_enable_ops[cpu]) | ||
304 | continue; | 333 | continue; |
305 | 334 | ||
306 | release_addr = __va(cpu_release_addr[cpu]); | 335 | err = smp_enable_ops[cpu]->prepare_cpu(cpu); |
307 | release_addr[0] = (void *)__pa(secondary_holding_pen); | 336 | if (err) |
308 | __flush_dcache_area(release_addr, sizeof(release_addr[0])); | 337 | continue; |
309 | 338 | ||
310 | set_cpu_present(cpu, true); | 339 | set_cpu_present(cpu, true); |
311 | max_cpus--; | 340 | max_cpus--; |
312 | } | 341 | } |
313 | |||
314 | /* | ||
315 | * Send an event to wake up the secondaries. | ||
316 | */ | ||
317 | sev(); | ||
318 | } | 342 | } |
319 | 343 | ||
320 | 344 | ||