122f287f4SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only 29c92b28eSAndrew Jones /* 39c92b28eSAndrew Jones * Boot secondary CPUs 49c92b28eSAndrew Jones * 59c92b28eSAndrew Jones * Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com> 69c92b28eSAndrew Jones */ 79c92b28eSAndrew Jones #include <libcflat.h> 80c39d9eaSAndrew Jones #include <alloc_page.h> 922f287f4SAndrew Jones #include <cpumask.h> 109c92b28eSAndrew Jones #include <asm/csr.h> 1192f91f64SAndrew Jones #include <asm/io.h> 120c39d9eaSAndrew Jones #include <asm/mmu.h> 139c92b28eSAndrew Jones #include <asm/page.h> 149c92b28eSAndrew Jones #include <asm/processor.h> 159c92b28eSAndrew Jones #include <asm/sbi.h> 169c92b28eSAndrew Jones #include <asm/smp.h> 1722f287f4SAndrew Jones 1822f287f4SAndrew Jones cpumask_t cpu_present_mask; 1922f287f4SAndrew Jones cpumask_t cpu_online_mask; 2022f287f4SAndrew Jones cpumask_t cpu_idle_mask; 219c92b28eSAndrew Jones 229c92b28eSAndrew Jones secondary_func_t secondary_cinit(struct secondary_data *data) 239c92b28eSAndrew Jones { 249c92b28eSAndrew Jones struct thread_info *info; 259c92b28eSAndrew Jones 260c39d9eaSAndrew Jones __mmu_enable(data->satp); 279c92b28eSAndrew Jones thread_info_init(); 2894ca1aafSAndrew Jones local_hart_init(); 299c92b28eSAndrew Jones info = current_thread_info(); 309c92b28eSAndrew Jones set_cpu_online(info->cpu, true); 319c92b28eSAndrew Jones smp_send_event(); 329c92b28eSAndrew Jones 339c92b28eSAndrew Jones return data->func; 349c92b28eSAndrew Jones } 359c92b28eSAndrew Jones 369c92b28eSAndrew Jones static void __smp_boot_secondary(int cpu, secondary_func_t func) 379c92b28eSAndrew Jones { 38*50fab1a5SAndrew Jones void *sp_mem = __va(cpus[cpu].sp); 39*50fab1a5SAndrew Jones struct secondary_data *data; 409c92b28eSAndrew Jones struct sbiret ret; 419c92b28eSAndrew Jones 42*50fab1a5SAndrew Jones if (!sp_mem) { 43*50fab1a5SAndrew Jones phys_addr_t sp_phys; 449c92b28eSAndrew Jones 45*50fab1a5SAndrew Jones sp_mem = alloc_pages(1) + SZ_8K - 16; 46*50fab1a5SAndrew Jones sp_phys = virt_to_phys(sp_mem); 47*50fab1a5SAndrew Jones cpus[cpu].sp = __pa(sp_phys); 4892f91f64SAndrew Jones 49*50fab1a5SAndrew Jones assert(__va(cpus[cpu].sp) == sp_mem); 50*50fab1a5SAndrew Jones } 51*50fab1a5SAndrew Jones 52*50fab1a5SAndrew Jones sp_mem -= sizeof(struct secondary_data); 53*50fab1a5SAndrew Jones data = (struct secondary_data *)sp_mem; 54*50fab1a5SAndrew Jones data->satp = csr_read(CSR_SATP); 55*50fab1a5SAndrew Jones data->stvec = csr_read(CSR_STVEC); 56*50fab1a5SAndrew Jones data->func = func; 57*50fab1a5SAndrew Jones 58*50fab1a5SAndrew Jones ret = sbi_hart_start(cpus[cpu].hartid, __pa(secondary_entry), cpus[cpu].sp); 599c92b28eSAndrew Jones assert(ret.error == SBI_SUCCESS); 609c92b28eSAndrew Jones } 619c92b28eSAndrew Jones 629c92b28eSAndrew Jones void smp_boot_secondary(int cpu, void (*func)(void)) 639c92b28eSAndrew Jones { 64*50fab1a5SAndrew Jones struct sbiret ret; 659c92b28eSAndrew Jones 66*50fab1a5SAndrew Jones do { 67*50fab1a5SAndrew Jones ret = sbi_hart_get_status(cpus[cpu].hartid); 68*50fab1a5SAndrew Jones assert(!ret.error); 69*50fab1a5SAndrew Jones } while (ret.value == SBI_EXT_HSM_STOP_PENDING); 70*50fab1a5SAndrew Jones 71*50fab1a5SAndrew Jones assert_msg(ret.value == SBI_EXT_HSM_STOPPED, "CPU%d is not stopped", cpu); 729c92b28eSAndrew Jones __smp_boot_secondary(cpu, func); 739c92b28eSAndrew Jones 749c92b28eSAndrew Jones while (!cpu_online(cpu)) 759c92b28eSAndrew Jones smp_wait_for_event(); 769c92b28eSAndrew Jones } 779c92b28eSAndrew Jones 789c92b28eSAndrew Jones void smp_boot_secondary_nofail(int cpu, void (*func)(void)) 799c92b28eSAndrew Jones { 80*50fab1a5SAndrew Jones struct sbiret ret; 819c92b28eSAndrew Jones 82*50fab1a5SAndrew Jones do { 83*50fab1a5SAndrew Jones ret = sbi_hart_get_status(cpus[cpu].hartid); 84*50fab1a5SAndrew Jones assert(!ret.error); 85*50fab1a5SAndrew Jones } while (ret.value == SBI_EXT_HSM_STOP_PENDING); 86*50fab1a5SAndrew Jones 87*50fab1a5SAndrew Jones if (ret.value == SBI_EXT_HSM_STOPPED) 889c92b28eSAndrew Jones __smp_boot_secondary(cpu, func); 89*50fab1a5SAndrew Jones else 90*50fab1a5SAndrew Jones assert_msg(ret.value == SBI_EXT_HSM_START_PENDING || ret.value == SBI_EXT_HSM_STARTED, 91*50fab1a5SAndrew Jones "CPU%d is in an unexpected state %ld", cpu, ret.value); 929c92b28eSAndrew Jones 939c92b28eSAndrew Jones while (!cpu_online(cpu)) 949c92b28eSAndrew Jones smp_wait_for_event(); 959c92b28eSAndrew Jones } 96