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/mmu.h> 12 #include <asm/page.h> 13 #include <asm/processor.h> 14 #include <asm/sbi.h> 15 #include <asm/smp.h> 16 17 cpumask_t cpu_present_mask; 18 cpumask_t cpu_online_mask; 19 cpumask_t cpu_idle_mask; 20 21 static cpumask_t cpu_started; 22 23 secondary_func_t secondary_cinit(struct secondary_data *data) 24 { 25 struct thread_info *info; 26 27 __mmu_enable(data->satp); 28 thread_info_init(); 29 info = current_thread_info(); 30 set_cpu_online(info->cpu, true); 31 smp_send_event(); 32 33 return data->func; 34 } 35 36 static void __smp_boot_secondary(int cpu, secondary_func_t func) 37 { 38 struct secondary_data *sp = alloc_pages(1) + SZ_8K - 16; 39 struct sbiret ret; 40 41 sp -= sizeof(struct secondary_data); 42 sp->satp = csr_read(CSR_SATP); 43 sp->stvec = csr_read(CSR_STVEC); 44 sp->func = func; 45 46 ret = sbi_hart_start(cpus[cpu].hartid, (unsigned long)&secondary_entry, __pa(sp)); 47 assert(ret.error == SBI_SUCCESS); 48 } 49 50 void smp_boot_secondary(int cpu, void (*func)(void)) 51 { 52 int ret = cpumask_test_and_set_cpu(cpu, &cpu_started); 53 54 assert_msg(!ret, "CPU%d already boot once", cpu); 55 __smp_boot_secondary(cpu, func); 56 57 while (!cpu_online(cpu)) 58 smp_wait_for_event(); 59 } 60 61 void smp_boot_secondary_nofail(int cpu, void (*func)(void)) 62 { 63 int ret = cpumask_test_and_set_cpu(cpu, &cpu_started); 64 65 if (!ret) 66 __smp_boot_secondary(cpu, func); 67 68 while (!cpu_online(cpu)) 69 smp_wait_for_event(); 70 } 71