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