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 secondary_func_t secondary_cinit(struct secondary_data *data) 23 { 24 struct thread_info *info; 25 26 __mmu_enable(data->satp); 27 thread_info_init(); 28 local_hart_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 void *sp_mem = __va(cpus[cpu].sp); 39 struct secondary_data *data; 40 struct sbiret ret; 41 42 if (!sp_mem) { 43 phys_addr_t sp_phys; 44 45 sp_mem = alloc_pages(1) + SZ_8K - 16; 46 sp_phys = virt_to_phys(sp_mem); 47 cpus[cpu].sp = __pa(sp_phys); 48 49 assert(__va(cpus[cpu].sp) == sp_mem); 50 } 51 52 sp_mem -= sizeof(struct secondary_data); 53 data = (struct secondary_data *)sp_mem; 54 data->satp = csr_read(CSR_SATP); 55 data->stvec = csr_read(CSR_STVEC); 56 data->func = func; 57 58 ret = sbi_hart_start(cpus[cpu].hartid, __pa(secondary_entry), cpus[cpu].sp); 59 assert(ret.error == SBI_SUCCESS); 60 } 61 62 void smp_boot_secondary(int cpu, void (*func)(void)) 63 { 64 struct sbiret ret; 65 66 do { 67 ret = sbi_hart_get_status(cpus[cpu].hartid); 68 assert(!ret.error); 69 } while (ret.value == SBI_EXT_HSM_STOP_PENDING); 70 71 assert_msg(ret.value == SBI_EXT_HSM_STOPPED, "CPU%d is not stopped", cpu); 72 __smp_boot_secondary(cpu, func); 73 74 while (!cpu_online(cpu)) 75 smp_wait_for_event(); 76 } 77 78 void smp_boot_secondary_nofail(int cpu, void (*func)(void)) 79 { 80 struct sbiret ret; 81 82 do { 83 ret = sbi_hart_get_status(cpus[cpu].hartid); 84 assert(!ret.error); 85 } while (ret.value == SBI_EXT_HSM_STOP_PENDING); 86 87 if (ret.value == SBI_EXT_HSM_STOPPED) 88 __smp_boot_secondary(cpu, func); 89 else 90 assert_msg(ret.value == SBI_EXT_HSM_START_PENDING || ret.value == SBI_EXT_HSM_STARTED, 91 "CPU%d is in an unexpected state %ld", cpu, ret.value); 92 93 while (!cpu_online(cpu)) 94 smp_wait_for_event(); 95 } 96