xref: /kvm-unit-tests/lib/arm/smp.c (revision 48d5952451de62a4db23cf73024f702cf1a64fc3)
1 /*
2  * Secondary cpu support
3  *
4  * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com>
5  *
6  * This work is licensed under the terms of the GNU LGPL, version 2.
7  */
8 #include <libcflat.h>
9 #include <auxinfo.h>
10 #include <cpumask.h>
11 #include <asm/thread_info.h>
12 #include <asm/spinlock.h>
13 #include <asm/mmu.h>
14 #include <asm/psci.h>
15 #include <asm/smp.h>
16 
17 cpumask_t cpu_present_mask;
18 cpumask_t cpu_online_mask;
19 cpumask_t cpu_idle_mask;
20 
21 struct secondary_data secondary_data;
22 static struct spinlock lock;
23 
24 /* Needed to compile with -Wmissing-prototypes */
25 secondary_entry_fn secondary_cinit(void);
26 
secondary_cinit(void)27 secondary_entry_fn secondary_cinit(void)
28 {
29 	struct thread_info *ti = current_thread_info();
30 	secondary_entry_fn entry;
31 
32 	thread_info_init(ti, 0);
33 
34 	if (!(auxinfo.flags & AUXINFO_MMU_OFF)) {
35 		ti->pgtable = mmu_idmap;
36 		mmu_mark_enabled(ti->cpu);
37 	}
38 
39 	/*
40 	 * Save secondary_data.entry locally to avoid opening a race
41 	 * window between marking ourselves online and calling it.
42 	 */
43 	entry = secondary_data.entry;
44 	set_cpu_online(ti->cpu, true);
45 	smp_send_event();
46 
47 	/*
48 	 * Return to the assembly stub, allowing entry to be called
49 	 * from there with an empty stack.
50 	 */
51 	return entry;
52 }
53 
__smp_boot_secondary(int cpu,secondary_entry_fn entry)54 static void __smp_boot_secondary(int cpu, secondary_entry_fn entry)
55 {
56 	int ret;
57 
58 	secondary_data.stack = thread_stack_alloc();
59 	secondary_data.entry = entry;
60 	mmu_mark_disabled(cpu);
61 	ret = cpu_psci_cpu_boot(cpu);
62 	assert(ret == 0);
63 
64 	while (!cpu_online(cpu))
65 		smp_wait_for_event();
66 }
67 
smp_boot_secondary(int cpu,secondary_entry_fn entry)68 void smp_boot_secondary(int cpu, secondary_entry_fn entry)
69 {
70 	spin_lock(&lock);
71 	assert_msg(!cpu_online(cpu), "CPU%d already boot once", cpu);
72 	__smp_boot_secondary(cpu, entry);
73 	spin_unlock(&lock);
74 }
75 
smp_boot_secondary_nofail(int cpu,secondary_entry_fn entry)76 void smp_boot_secondary_nofail(int cpu, secondary_entry_fn entry)
77 {
78 	spin_lock(&lock);
79 	if (!cpu_online(cpu))
80 		__smp_boot_secondary(cpu, entry);
81 	spin_unlock(&lock);
82 }
83