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