1 /* 2 * Secondary cpu support 3 * 4 * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com> 5 * 6 * This work is licensed under the terms of the GNU LGPL, version 2. 7 */ 8 #include <libcflat.h> 9 #include <auxinfo.h> 10 #include <cpumask.h> 11 #include <asm/thread_info.h> 12 #include <asm/spinlock.h> 13 #include <asm/mmu.h> 14 #include <asm/psci.h> 15 #include <asm/smp.h> 16 17 cpumask_t cpu_present_mask; 18 cpumask_t cpu_online_mask; 19 cpumask_t cpu_idle_mask; 20 21 struct secondary_data secondary_data; 22 static struct spinlock lock; 23 24 /* Needed to compile with -Wmissing-prototypes */ 25 secondary_entry_fn secondary_cinit(void); 26 27 secondary_entry_fn secondary_cinit(void) 28 { 29 struct thread_info *ti = current_thread_info(); 30 secondary_entry_fn entry; 31 32 thread_info_init(ti, 0); 33 34 if (!(auxinfo.flags & AUXINFO_MMU_OFF)) { 35 ti->pgtable = mmu_idmap; 36 mmu_mark_enabled(ti->cpu); 37 } 38 39 /* 40 * Save secondary_data.entry locally to avoid opening a race 41 * window between marking ourselves online and calling it. 42 */ 43 entry = secondary_data.entry; 44 set_cpu_online(ti->cpu, true); 45 smp_send_event(); 46 47 /* 48 * Return to the assembly stub, allowing entry to be called 49 * from there with an empty stack. 50 */ 51 return entry; 52 } 53 54 static void __smp_boot_secondary(int cpu, secondary_entry_fn entry) 55 { 56 int ret; 57 58 secondary_data.stack = thread_stack_alloc(); 59 secondary_data.entry = entry; 60 mmu_mark_disabled(cpu); 61 ret = cpu_psci_cpu_boot(cpu); 62 assert(ret == 0); 63 64 while (!cpu_online(cpu)) 65 smp_wait_for_event(); 66 } 67 68 void smp_boot_secondary(int cpu, secondary_entry_fn entry) 69 { 70 spin_lock(&lock); 71 assert_msg(!cpu_online(cpu), "CPU%d already boot once", cpu); 72 __smp_boot_secondary(cpu, entry); 73 spin_unlock(&lock); 74 } 75 76 void smp_boot_secondary_nofail(int cpu, secondary_entry_fn entry) 77 { 78 spin_lock(&lock); 79 if (!cpu_online(cpu)) 80 __smp_boot_secondary(cpu, entry); 81 spin_unlock(&lock); 82 } 83