xref: /kvm-unit-tests/lib/arm/smp.c (revision 543ce33ca386130ac16694f38a4933125a59182c)
168ea0e0bSAndrew Jones /*
268ea0e0bSAndrew Jones  * Secondary cpu support
368ea0e0bSAndrew Jones  *
468ea0e0bSAndrew Jones  * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com>
568ea0e0bSAndrew Jones  *
668ea0e0bSAndrew Jones  * This work is licensed under the terms of the GNU LGPL, version 2.
768ea0e0bSAndrew Jones  */
868ea0e0bSAndrew Jones #include <libcflat.h>
968ea0e0bSAndrew Jones #include <asm/thread_info.h>
1068ea0e0bSAndrew Jones #include <asm/cpumask.h>
111742c67aSAndrew Jones #include <asm/barrier.h>
1268ea0e0bSAndrew Jones #include <asm/mmu.h>
1368ea0e0bSAndrew Jones #include <asm/psci.h>
1468ea0e0bSAndrew Jones #include <asm/smp.h>
1568ea0e0bSAndrew Jones 
1668ea0e0bSAndrew Jones cpumask_t cpu_present_mask;
1768ea0e0bSAndrew Jones cpumask_t cpu_online_mask;
18*543ce33cSAndrew Jones cpumask_t cpu_halted_mask;
1968ea0e0bSAndrew Jones struct secondary_data secondary_data;
2068ea0e0bSAndrew Jones 
2168ea0e0bSAndrew Jones secondary_entry_fn secondary_cinit(void)
2268ea0e0bSAndrew Jones {
2368ea0e0bSAndrew Jones 	struct thread_info *ti = current_thread_info();
2468ea0e0bSAndrew Jones 	secondary_entry_fn entry;
2568ea0e0bSAndrew Jones 
2668ea0e0bSAndrew Jones 	thread_info_init(ti, 0);
271742c67aSAndrew Jones 	mmu_mark_enabled(ti->cpu);
2868ea0e0bSAndrew Jones 
2968ea0e0bSAndrew Jones 	/*
3068ea0e0bSAndrew Jones 	 * Save secondary_data.entry locally to avoid opening a race
3168ea0e0bSAndrew Jones 	 * window between marking ourselves online and calling it.
3268ea0e0bSAndrew Jones 	 */
3368ea0e0bSAndrew Jones 	entry = secondary_data.entry;
3468ea0e0bSAndrew Jones 	set_cpu_online(ti->cpu, true);
3568ea0e0bSAndrew Jones 	sev();
3668ea0e0bSAndrew Jones 
3768ea0e0bSAndrew Jones 	/*
3868ea0e0bSAndrew Jones 	 * Return to the assembly stub, allowing entry to be called
3968ea0e0bSAndrew Jones 	 * from there with an empty stack.
4068ea0e0bSAndrew Jones 	 */
4168ea0e0bSAndrew Jones 	return entry;
4268ea0e0bSAndrew Jones }
4368ea0e0bSAndrew Jones 
4468ea0e0bSAndrew Jones void smp_boot_secondary(int cpu, secondary_entry_fn entry)
4568ea0e0bSAndrew Jones {
4618ab6cadSAndrew Jones 	int ret;
4768ea0e0bSAndrew Jones 
48632f935cSAndrew Jones 	secondary_data.stack = thread_stack_alloc();
4968ea0e0bSAndrew Jones 	secondary_data.entry = entry;
501742c67aSAndrew Jones 	mmu_mark_disabled(cpu);
5118ab6cadSAndrew Jones 	ret = cpu_psci_cpu_boot(cpu);
5218ab6cadSAndrew Jones 	assert(ret == 0);
5368ea0e0bSAndrew Jones 
5468ea0e0bSAndrew Jones 	while (!cpu_online(cpu))
5568ea0e0bSAndrew Jones 		wfe();
5668ea0e0bSAndrew Jones }
57*543ce33cSAndrew Jones 
58*543ce33cSAndrew Jones void secondary_halt(void)
59*543ce33cSAndrew Jones {
60*543ce33cSAndrew Jones 	struct thread_info *ti = current_thread_info();
61*543ce33cSAndrew Jones 
62*543ce33cSAndrew Jones 	cpumask_set_cpu(ti->cpu, &cpu_halted_mask);
63*543ce33cSAndrew Jones 	halt();
64*543ce33cSAndrew Jones }
65*543ce33cSAndrew Jones 
66*543ce33cSAndrew Jones void smp_run(void (*func)(void))
67*543ce33cSAndrew Jones {
68*543ce33cSAndrew Jones 	int cpu;
69*543ce33cSAndrew Jones 
70*543ce33cSAndrew Jones 	for_each_present_cpu(cpu) {
71*543ce33cSAndrew Jones 		if (cpu == 0)
72*543ce33cSAndrew Jones 			continue;
73*543ce33cSAndrew Jones 		smp_boot_secondary(cpu, func);
74*543ce33cSAndrew Jones 	}
75*543ce33cSAndrew Jones 	func();
76*543ce33cSAndrew Jones 
77*543ce33cSAndrew Jones 	cpumask_set_cpu(0, &cpu_halted_mask);
78*543ce33cSAndrew Jones 	while (!cpumask_full(&cpu_halted_mask))
79*543ce33cSAndrew Jones 		cpu_relax();
80*543ce33cSAndrew Jones 	cpumask_clear_cpu(0, &cpu_halted_mask);
81*543ce33cSAndrew Jones }
82