xref: /kvm-unit-tests/lib/arm/smp.c (revision 48d5952451de62a4db23cf73024f702cf1a64fc3)
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>
962bdc67fSAndrew Jones #include <auxinfo.h>
10dfc1fec2SAndrew Jones #include <cpumask.h>
1168ea0e0bSAndrew Jones #include <asm/thread_info.h>
12ff942175SAndrew Jones #include <asm/spinlock.h>
1368ea0e0bSAndrew Jones #include <asm/mmu.h>
1468ea0e0bSAndrew Jones #include <asm/psci.h>
1568ea0e0bSAndrew Jones #include <asm/smp.h>
1668ea0e0bSAndrew Jones 
1768ea0e0bSAndrew Jones cpumask_t cpu_present_mask;
1868ea0e0bSAndrew Jones cpumask_t cpu_online_mask;
199246de4cSAndrew Jones cpumask_t cpu_idle_mask;
20ff942175SAndrew Jones 
2168ea0e0bSAndrew Jones struct secondary_data secondary_data;
22ff942175SAndrew Jones static struct spinlock lock;
2368ea0e0bSAndrew Jones 
240df901e0SAndrew Jones /* Needed to compile with -Wmissing-prototypes */
250df901e0SAndrew Jones secondary_entry_fn secondary_cinit(void);
260df901e0SAndrew Jones 
secondary_cinit(void)2768ea0e0bSAndrew Jones secondary_entry_fn secondary_cinit(void)
2868ea0e0bSAndrew Jones {
2968ea0e0bSAndrew Jones 	struct thread_info *ti = current_thread_info();
3068ea0e0bSAndrew Jones 	secondary_entry_fn entry;
3168ea0e0bSAndrew Jones 
3268ea0e0bSAndrew Jones 	thread_info_init(ti, 0);
3362bdc67fSAndrew Jones 
3462bdc67fSAndrew Jones 	if (!(auxinfo.flags & AUXINFO_MMU_OFF)) {
3536b50de9SAndrew Jones 		ti->pgtable = mmu_idmap;
361742c67aSAndrew Jones 		mmu_mark_enabled(ti->cpu);
3762bdc67fSAndrew Jones 	}
3868ea0e0bSAndrew Jones 
3968ea0e0bSAndrew Jones 	/*
4068ea0e0bSAndrew Jones 	 * Save secondary_data.entry locally to avoid opening a race
4168ea0e0bSAndrew Jones 	 * window between marking ourselves online and calling it.
4268ea0e0bSAndrew Jones 	 */
4368ea0e0bSAndrew Jones 	entry = secondary_data.entry;
4468ea0e0bSAndrew Jones 	set_cpu_online(ti->cpu, true);
4505a76472SAndrew Jones 	smp_send_event();
4668ea0e0bSAndrew Jones 
4768ea0e0bSAndrew Jones 	/*
4868ea0e0bSAndrew Jones 	 * Return to the assembly stub, allowing entry to be called
4968ea0e0bSAndrew Jones 	 * from there with an empty stack.
5068ea0e0bSAndrew Jones 	 */
5168ea0e0bSAndrew Jones 	return entry;
5268ea0e0bSAndrew Jones }
5368ea0e0bSAndrew Jones 
__smp_boot_secondary(int cpu,secondary_entry_fn entry)54e713fd55SAndrew Jones static void __smp_boot_secondary(int cpu, secondary_entry_fn entry)
5568ea0e0bSAndrew Jones {
5618ab6cadSAndrew Jones 	int ret;
5768ea0e0bSAndrew Jones 
58632f935cSAndrew Jones 	secondary_data.stack = thread_stack_alloc();
5968ea0e0bSAndrew Jones 	secondary_data.entry = entry;
601742c67aSAndrew Jones 	mmu_mark_disabled(cpu);
6118ab6cadSAndrew Jones 	ret = cpu_psci_cpu_boot(cpu);
6218ab6cadSAndrew Jones 	assert(ret == 0);
6368ea0e0bSAndrew Jones 
6468ea0e0bSAndrew Jones 	while (!cpu_online(cpu))
6505a76472SAndrew Jones 		smp_wait_for_event();
66e713fd55SAndrew Jones }
67ff942175SAndrew Jones 
smp_boot_secondary(int cpu,secondary_entry_fn entry)68e713fd55SAndrew Jones void smp_boot_secondary(int cpu, secondary_entry_fn entry)
69e713fd55SAndrew Jones {
70e713fd55SAndrew Jones 	spin_lock(&lock);
71e713fd55SAndrew Jones 	assert_msg(!cpu_online(cpu), "CPU%d already boot once", cpu);
72e713fd55SAndrew Jones 	__smp_boot_secondary(cpu, entry);
73ff942175SAndrew Jones 	spin_unlock(&lock);
7468ea0e0bSAndrew Jones }
75543ce33cSAndrew Jones 
smp_boot_secondary_nofail(int cpu,secondary_entry_fn entry)76*01855004SAndrew Jones void smp_boot_secondary_nofail(int cpu, secondary_entry_fn entry)
77*01855004SAndrew Jones {
78*01855004SAndrew Jones 	spin_lock(&lock);
79*01855004SAndrew Jones 	if (!cpu_online(cpu))
80*01855004SAndrew Jones 		__smp_boot_secondary(cpu, entry);
81*01855004SAndrew Jones 	spin_unlock(&lock);
82*01855004SAndrew Jones }
83