xref: /kvm-unit-tests/lib/riscv/smp.c (revision 71f7db53297d39b7d9b779d6ecbd49f0d8da1dfc)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Boot secondary CPUs
4  *
5  * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
6  */
7 #include <libcflat.h>
8 #include <alloc_page.h>
9 #include <cpumask.h>
10 #include <asm/csr.h>
11 #include <asm/io.h>
12 #include <asm/mmu.h>
13 #include <asm/page.h>
14 #include <asm/processor.h>
15 #include <asm/sbi.h>
16 #include <asm/smp.h>
17 
18 cpumask_t cpu_present_mask;
19 cpumask_t cpu_online_mask;
20 cpumask_t cpu_idle_mask;
21 
secondary_cinit(struct secondary_data * data)22 secondary_func_t secondary_cinit(struct secondary_data *data)
23 {
24 	struct thread_info *info;
25 
26 	__mmu_enable(data->satp);
27 	thread_info_init();
28 	local_hart_init();
29 	info = current_thread_info();
30 	set_cpu_online(info->cpu, true);
31 	smp_send_event();
32 
33 	return data->func;
34 }
35 
__smp_boot_secondary(int cpu,secondary_func_t func)36 static void __smp_boot_secondary(int cpu, secondary_func_t func)
37 {
38 	void *sp_mem = __va(cpus[cpu].sp);
39 	struct secondary_data *data;
40 	struct sbiret ret;
41 
42 	if (!sp_mem) {
43 		phys_addr_t sp_phys;
44 
45 		sp_mem = alloc_pages(1) + SZ_8K - 16;
46 		sp_phys = virt_to_phys(sp_mem);
47 		cpus[cpu].sp = __pa(sp_phys);
48 
49 		assert(__va(cpus[cpu].sp) == sp_mem);
50 	}
51 
52 	sp_mem -= sizeof(struct secondary_data);
53 	data = (struct secondary_data *)sp_mem;
54 	data->satp = csr_read(CSR_SATP);
55 	data->stvec = csr_read(CSR_STVEC);
56 	data->func = func;
57 
58 	ret = sbi_hart_start(cpus[cpu].hartid, __pa(secondary_entry), cpus[cpu].sp);
59 	assert(ret.error == SBI_SUCCESS);
60 }
61 
smp_boot_secondary(int cpu,void (* func)(void))62 void smp_boot_secondary(int cpu, void (*func)(void))
63 {
64 	struct sbiret ret;
65 
66 	do {
67 		ret = sbi_hart_get_status(cpus[cpu].hartid);
68 		assert(!ret.error);
69 	} while (ret.value == SBI_EXT_HSM_STOP_PENDING);
70 
71 	assert_msg(ret.value == SBI_EXT_HSM_STOPPED, "CPU%d is not stopped", cpu);
72 	__smp_boot_secondary(cpu, func);
73 
74 	while (!cpu_online(cpu))
75 		smp_wait_for_event();
76 }
77 
smp_boot_secondary_nofail(int cpu,void (* func)(void))78 void smp_boot_secondary_nofail(int cpu, void (*func)(void))
79 {
80 	struct sbiret ret;
81 
82 	do {
83 		ret = sbi_hart_get_status(cpus[cpu].hartid);
84 		assert(!ret.error);
85 	} while (ret.value == SBI_EXT_HSM_STOP_PENDING);
86 
87 	if (ret.value == SBI_EXT_HSM_STOPPED)
88 		__smp_boot_secondary(cpu, func);
89 	else
90 		assert_msg(ret.value == SBI_EXT_HSM_START_PENDING || ret.value == SBI_EXT_HSM_STARTED,
91 			   "CPU%d is in an unexpected state %ld", cpu, ret.value);
92 
93 	while (!cpu_online(cpu))
94 		smp_wait_for_event();
95 }
96