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 static cpumask_t cpu_started; 239c92b28eSAndrew Jones 249c92b28eSAndrew Jones secondary_func_t secondary_cinit(struct secondary_data *data) 259c92b28eSAndrew Jones { 269c92b28eSAndrew Jones struct thread_info *info; 279c92b28eSAndrew Jones 280c39d9eaSAndrew Jones __mmu_enable(data->satp); 299c92b28eSAndrew Jones thread_info_init(); 30*94ca1aafSAndrew Jones local_hart_init(); 319c92b28eSAndrew Jones info = current_thread_info(); 329c92b28eSAndrew Jones set_cpu_online(info->cpu, true); 339c92b28eSAndrew Jones smp_send_event(); 349c92b28eSAndrew Jones 359c92b28eSAndrew Jones return data->func; 369c92b28eSAndrew Jones } 379c92b28eSAndrew Jones 389c92b28eSAndrew Jones static void __smp_boot_secondary(int cpu, secondary_func_t func) 399c92b28eSAndrew Jones { 400c39d9eaSAndrew Jones struct secondary_data *sp = alloc_pages(1) + SZ_8K - 16; 4192f91f64SAndrew Jones phys_addr_t sp_phys; 429c92b28eSAndrew Jones struct sbiret ret; 439c92b28eSAndrew Jones 449c92b28eSAndrew Jones sp -= sizeof(struct secondary_data); 450c39d9eaSAndrew Jones sp->satp = csr_read(CSR_SATP); 469c92b28eSAndrew Jones sp->stvec = csr_read(CSR_STVEC); 479c92b28eSAndrew Jones sp->func = func; 489c92b28eSAndrew Jones 4992f91f64SAndrew Jones sp_phys = virt_to_phys(sp); 5092f91f64SAndrew Jones assert(sp_phys == __pa(sp_phys)); 5192f91f64SAndrew Jones 5292f91f64SAndrew Jones ret = sbi_hart_start(cpus[cpu].hartid, (unsigned long)&secondary_entry, __pa(sp_phys)); 539c92b28eSAndrew Jones assert(ret.error == SBI_SUCCESS); 549c92b28eSAndrew Jones } 559c92b28eSAndrew Jones 569c92b28eSAndrew Jones void smp_boot_secondary(int cpu, void (*func)(void)) 579c92b28eSAndrew Jones { 589c92b28eSAndrew Jones int ret = cpumask_test_and_set_cpu(cpu, &cpu_started); 599c92b28eSAndrew Jones 609c92b28eSAndrew Jones assert_msg(!ret, "CPU%d already boot once", cpu); 619c92b28eSAndrew Jones __smp_boot_secondary(cpu, func); 629c92b28eSAndrew Jones 639c92b28eSAndrew Jones while (!cpu_online(cpu)) 649c92b28eSAndrew Jones smp_wait_for_event(); 659c92b28eSAndrew Jones } 669c92b28eSAndrew Jones 679c92b28eSAndrew Jones void smp_boot_secondary_nofail(int cpu, void (*func)(void)) 689c92b28eSAndrew Jones { 699c92b28eSAndrew Jones int ret = cpumask_test_and_set_cpu(cpu, &cpu_started); 709c92b28eSAndrew Jones 719c92b28eSAndrew Jones if (!ret) 729c92b28eSAndrew Jones __smp_boot_secondary(cpu, func); 739c92b28eSAndrew Jones 749c92b28eSAndrew Jones while (!cpu_online(cpu)) 759c92b28eSAndrew Jones smp_wait_for_event(); 769c92b28eSAndrew Jones } 77