xref: /kvm-unit-tests/lib/riscv/smp.c (revision 94ca1aaf8c34410cb89f1d7ee3bd4642a39c009e)
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>
80c39d9eaSAndrew Jones #include <alloc_page.h>
922f287f4SAndrew Jones #include <cpumask.h>
109c92b28eSAndrew Jones #include <asm/csr.h>
1192f91f64SAndrew Jones #include <asm/io.h>
120c39d9eaSAndrew Jones #include <asm/mmu.h>
139c92b28eSAndrew Jones #include <asm/page.h>
149c92b28eSAndrew Jones #include <asm/processor.h>
159c92b28eSAndrew Jones #include <asm/sbi.h>
169c92b28eSAndrew Jones #include <asm/smp.h>
1722f287f4SAndrew Jones 
1822f287f4SAndrew Jones cpumask_t cpu_present_mask;
1922f287f4SAndrew Jones cpumask_t cpu_online_mask;
2022f287f4SAndrew Jones cpumask_t cpu_idle_mask;
219c92b28eSAndrew Jones 
229c92b28eSAndrew Jones static cpumask_t cpu_started;
239c92b28eSAndrew Jones 
249c92b28eSAndrew Jones secondary_func_t secondary_cinit(struct secondary_data *data)
259c92b28eSAndrew Jones {
269c92b28eSAndrew Jones 	struct thread_info *info;
279c92b28eSAndrew Jones 
280c39d9eaSAndrew Jones 	__mmu_enable(data->satp);
299c92b28eSAndrew Jones 	thread_info_init();
30*94ca1aafSAndrew Jones 	local_hart_init();
319c92b28eSAndrew Jones 	info = current_thread_info();
329c92b28eSAndrew Jones 	set_cpu_online(info->cpu, true);
339c92b28eSAndrew Jones 	smp_send_event();
349c92b28eSAndrew Jones 
359c92b28eSAndrew Jones 	return data->func;
369c92b28eSAndrew Jones }
379c92b28eSAndrew Jones 
389c92b28eSAndrew Jones static void __smp_boot_secondary(int cpu, secondary_func_t func)
399c92b28eSAndrew Jones {
400c39d9eaSAndrew Jones 	struct secondary_data *sp = alloc_pages(1) + SZ_8K - 16;
4192f91f64SAndrew Jones 	phys_addr_t sp_phys;
429c92b28eSAndrew Jones 	struct sbiret ret;
439c92b28eSAndrew Jones 
449c92b28eSAndrew Jones 	sp -= sizeof(struct secondary_data);
450c39d9eaSAndrew Jones 	sp->satp = csr_read(CSR_SATP);
469c92b28eSAndrew Jones 	sp->stvec = csr_read(CSR_STVEC);
479c92b28eSAndrew Jones 	sp->func = func;
489c92b28eSAndrew Jones 
4992f91f64SAndrew Jones 	sp_phys = virt_to_phys(sp);
5092f91f64SAndrew Jones 	assert(sp_phys == __pa(sp_phys));
5192f91f64SAndrew Jones 
5292f91f64SAndrew Jones 	ret = sbi_hart_start(cpus[cpu].hartid, (unsigned long)&secondary_entry, __pa(sp_phys));
539c92b28eSAndrew Jones 	assert(ret.error == SBI_SUCCESS);
549c92b28eSAndrew Jones }
559c92b28eSAndrew Jones 
569c92b28eSAndrew Jones void smp_boot_secondary(int cpu, void (*func)(void))
579c92b28eSAndrew Jones {
589c92b28eSAndrew Jones 	int ret = cpumask_test_and_set_cpu(cpu, &cpu_started);
599c92b28eSAndrew Jones 
609c92b28eSAndrew Jones 	assert_msg(!ret, "CPU%d already boot once", cpu);
619c92b28eSAndrew Jones 	__smp_boot_secondary(cpu, func);
629c92b28eSAndrew Jones 
639c92b28eSAndrew Jones 	while (!cpu_online(cpu))
649c92b28eSAndrew Jones 		smp_wait_for_event();
659c92b28eSAndrew Jones }
669c92b28eSAndrew Jones 
679c92b28eSAndrew Jones void smp_boot_secondary_nofail(int cpu, void (*func)(void))
689c92b28eSAndrew Jones {
699c92b28eSAndrew Jones 	int ret = cpumask_test_and_set_cpu(cpu, &cpu_started);
709c92b28eSAndrew Jones 
719c92b28eSAndrew Jones 	if (!ret)
729c92b28eSAndrew Jones 		__smp_boot_secondary(cpu, func);
739c92b28eSAndrew Jones 
749c92b28eSAndrew Jones 	while (!cpu_online(cpu))
759c92b28eSAndrew Jones 		smp_wait_for_event();
769c92b28eSAndrew Jones }
77