xref: /kvm-unit-tests/lib/riscv/smp.c (revision 92f91f64bc722ce8cced0f27e6d486f915cf0011)
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>
11*92f91f64SAndrew 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();
309c92b28eSAndrew Jones 	info = current_thread_info();
319c92b28eSAndrew Jones 	set_cpu_online(info->cpu, true);
329c92b28eSAndrew Jones 	smp_send_event();
339c92b28eSAndrew Jones 
349c92b28eSAndrew Jones 	return data->func;
359c92b28eSAndrew Jones }
369c92b28eSAndrew Jones 
379c92b28eSAndrew Jones static void __smp_boot_secondary(int cpu, secondary_func_t func)
389c92b28eSAndrew Jones {
390c39d9eaSAndrew Jones 	struct secondary_data *sp = alloc_pages(1) + SZ_8K - 16;
40*92f91f64SAndrew Jones 	phys_addr_t sp_phys;
419c92b28eSAndrew Jones 	struct sbiret ret;
429c92b28eSAndrew Jones 
439c92b28eSAndrew Jones 	sp -= sizeof(struct secondary_data);
440c39d9eaSAndrew Jones 	sp->satp = csr_read(CSR_SATP);
459c92b28eSAndrew Jones 	sp->stvec = csr_read(CSR_STVEC);
469c92b28eSAndrew Jones 	sp->func = func;
479c92b28eSAndrew Jones 
48*92f91f64SAndrew Jones 	sp_phys = virt_to_phys(sp);
49*92f91f64SAndrew Jones 	assert(sp_phys == __pa(sp_phys));
50*92f91f64SAndrew Jones 
51*92f91f64SAndrew Jones 	ret = sbi_hart_start(cpus[cpu].hartid, (unsigned long)&secondary_entry, __pa(sp_phys));
529c92b28eSAndrew Jones 	assert(ret.error == SBI_SUCCESS);
539c92b28eSAndrew Jones }
549c92b28eSAndrew Jones 
559c92b28eSAndrew Jones void smp_boot_secondary(int cpu, void (*func)(void))
569c92b28eSAndrew Jones {
579c92b28eSAndrew Jones 	int ret = cpumask_test_and_set_cpu(cpu, &cpu_started);
589c92b28eSAndrew Jones 
599c92b28eSAndrew Jones 	assert_msg(!ret, "CPU%d already boot once", cpu);
609c92b28eSAndrew Jones 	__smp_boot_secondary(cpu, func);
619c92b28eSAndrew Jones 
629c92b28eSAndrew Jones 	while (!cpu_online(cpu))
639c92b28eSAndrew Jones 		smp_wait_for_event();
649c92b28eSAndrew Jones }
659c92b28eSAndrew Jones 
669c92b28eSAndrew Jones void smp_boot_secondary_nofail(int cpu, void (*func)(void))
679c92b28eSAndrew Jones {
689c92b28eSAndrew Jones 	int ret = cpumask_test_and_set_cpu(cpu, &cpu_started);
699c92b28eSAndrew Jones 
709c92b28eSAndrew Jones 	if (!ret)
719c92b28eSAndrew Jones 		__smp_boot_secondary(cpu, func);
729c92b28eSAndrew Jones 
739c92b28eSAndrew Jones 	while (!cpu_online(cpu))
749c92b28eSAndrew Jones 		smp_wait_for_event();
759c92b28eSAndrew Jones }
76