// SPDX-License-Identifier: GPL-2.0-only /* * Boot secondary CPUs * * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones */ #include #include #include #include #include #include #include #include #include #include cpumask_t cpu_present_mask; cpumask_t cpu_online_mask; cpumask_t cpu_idle_mask; secondary_func_t secondary_cinit(struct secondary_data *data) { struct thread_info *info; __mmu_enable(data->satp); thread_info_init(); local_hart_init(); info = current_thread_info(); set_cpu_online(info->cpu, true); smp_send_event(); return data->func; } static void __smp_boot_secondary(int cpu, secondary_func_t func) { void *sp_mem = __va(cpus[cpu].sp); struct secondary_data *data; struct sbiret ret; if (!sp_mem) { phys_addr_t sp_phys; sp_mem = alloc_pages(1) + SZ_8K - 16; sp_phys = virt_to_phys(sp_mem); cpus[cpu].sp = __pa(sp_phys); assert(__va(cpus[cpu].sp) == sp_mem); } sp_mem -= sizeof(struct secondary_data); data = (struct secondary_data *)sp_mem; data->satp = csr_read(CSR_SATP); data->stvec = csr_read(CSR_STVEC); data->func = func; ret = sbi_hart_start(cpus[cpu].hartid, __pa(secondary_entry), cpus[cpu].sp); assert(ret.error == SBI_SUCCESS); } void smp_boot_secondary(int cpu, void (*func)(void)) { struct sbiret ret; do { ret = sbi_hart_get_status(cpus[cpu].hartid); assert(!ret.error); } while (ret.value == SBI_EXT_HSM_STOP_PENDING); assert_msg(ret.value == SBI_EXT_HSM_STOPPED, "CPU%d is not stopped", cpu); __smp_boot_secondary(cpu, func); while (!cpu_online(cpu)) smp_wait_for_event(); } void smp_boot_secondary_nofail(int cpu, void (*func)(void)) { struct sbiret ret; do { ret = sbi_hart_get_status(cpus[cpu].hartid); assert(!ret.error); } while (ret.value == SBI_EXT_HSM_STOP_PENDING); if (ret.value == SBI_EXT_HSM_STOPPED) __smp_boot_secondary(cpu, func); else assert_msg(ret.value == SBI_EXT_HSM_START_PENDING || ret.value == SBI_EXT_HSM_STARTED, "CPU%d is in an unexpected state %ld", cpu, ret.value); while (!cpu_online(cpu)) smp_wait_for_event(); }