xref: /kvm-unit-tests/lib/riscv/smp.c (revision 0c39d9ea9e5bcb4ac687dce5ceb8f13b1cb61cf4)
122f287f4SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only
29c92b28eSAndrew Jones /*
39c92b28eSAndrew Jones  * Boot secondary CPUs
49c92b28eSAndrew Jones  *
59c92b28eSAndrew Jones  * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
69c92b28eSAndrew Jones  */
79c92b28eSAndrew Jones #include <libcflat.h>
8*0c39d9eaSAndrew Jones #include <alloc_page.h>
922f287f4SAndrew Jones #include <cpumask.h>
109c92b28eSAndrew Jones #include <asm/csr.h>
11*0c39d9eaSAndrew Jones #include <asm/mmu.h>
129c92b28eSAndrew Jones #include <asm/page.h>
139c92b28eSAndrew Jones #include <asm/processor.h>
149c92b28eSAndrew Jones #include <asm/sbi.h>
159c92b28eSAndrew Jones #include <asm/smp.h>
1622f287f4SAndrew Jones 
1722f287f4SAndrew Jones cpumask_t cpu_present_mask;
1822f287f4SAndrew Jones cpumask_t cpu_online_mask;
1922f287f4SAndrew Jones cpumask_t cpu_idle_mask;
209c92b28eSAndrew Jones 
219c92b28eSAndrew Jones static cpumask_t cpu_started;
229c92b28eSAndrew Jones 
239c92b28eSAndrew Jones secondary_func_t secondary_cinit(struct secondary_data *data)
249c92b28eSAndrew Jones {
259c92b28eSAndrew Jones 	struct thread_info *info;
269c92b28eSAndrew Jones 
27*0c39d9eaSAndrew Jones 	__mmu_enable(data->satp);
289c92b28eSAndrew Jones 	thread_info_init();
299c92b28eSAndrew Jones 	info = current_thread_info();
309c92b28eSAndrew Jones 	set_cpu_online(info->cpu, true);
319c92b28eSAndrew Jones 	smp_send_event();
329c92b28eSAndrew Jones 
339c92b28eSAndrew Jones 	return data->func;
349c92b28eSAndrew Jones }
359c92b28eSAndrew Jones 
369c92b28eSAndrew Jones static void __smp_boot_secondary(int cpu, secondary_func_t func)
379c92b28eSAndrew Jones {
38*0c39d9eaSAndrew Jones 	struct secondary_data *sp = alloc_pages(1) + SZ_8K - 16;
399c92b28eSAndrew Jones 	struct sbiret ret;
409c92b28eSAndrew Jones 
419c92b28eSAndrew Jones 	sp -= sizeof(struct secondary_data);
42*0c39d9eaSAndrew Jones 	sp->satp = csr_read(CSR_SATP);
439c92b28eSAndrew Jones 	sp->stvec = csr_read(CSR_STVEC);
449c92b28eSAndrew Jones 	sp->func = func;
459c92b28eSAndrew Jones 
469c92b28eSAndrew Jones 	ret = sbi_hart_start(cpus[cpu].hartid, (unsigned long)&secondary_entry, __pa(sp));
479c92b28eSAndrew Jones 	assert(ret.error == SBI_SUCCESS);
489c92b28eSAndrew Jones }
499c92b28eSAndrew Jones 
509c92b28eSAndrew Jones void smp_boot_secondary(int cpu, void (*func)(void))
519c92b28eSAndrew Jones {
529c92b28eSAndrew Jones 	int ret = cpumask_test_and_set_cpu(cpu, &cpu_started);
539c92b28eSAndrew Jones 
549c92b28eSAndrew Jones 	assert_msg(!ret, "CPU%d already boot once", cpu);
559c92b28eSAndrew Jones 	__smp_boot_secondary(cpu, func);
569c92b28eSAndrew Jones 
579c92b28eSAndrew Jones 	while (!cpu_online(cpu))
589c92b28eSAndrew Jones 		smp_wait_for_event();
599c92b28eSAndrew Jones }
609c92b28eSAndrew Jones 
619c92b28eSAndrew Jones void smp_boot_secondary_nofail(int cpu, void (*func)(void))
629c92b28eSAndrew Jones {
639c92b28eSAndrew Jones 	int ret = cpumask_test_and_set_cpu(cpu, &cpu_started);
649c92b28eSAndrew Jones 
659c92b28eSAndrew Jones 	if (!ret)
669c92b28eSAndrew Jones 		__smp_boot_secondary(cpu, func);
679c92b28eSAndrew Jones 
689c92b28eSAndrew Jones 	while (!cpu_online(cpu))
699c92b28eSAndrew Jones 		smp_wait_for_event();
709c92b28eSAndrew Jones }
71