168ea0e0bSAndrew Jones /* 268ea0e0bSAndrew Jones * Secondary cpu support 368ea0e0bSAndrew Jones * 468ea0e0bSAndrew Jones * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com> 568ea0e0bSAndrew Jones * 668ea0e0bSAndrew Jones * This work is licensed under the terms of the GNU LGPL, version 2. 768ea0e0bSAndrew Jones */ 868ea0e0bSAndrew Jones #include <libcflat.h> 968ea0e0bSAndrew Jones #include <asm/thread_info.h> 1068ea0e0bSAndrew Jones #include <asm/cpumask.h> 111742c67aSAndrew Jones #include <asm/barrier.h> 1268ea0e0bSAndrew Jones #include <asm/mmu.h> 1368ea0e0bSAndrew Jones #include <asm/psci.h> 1468ea0e0bSAndrew Jones #include <asm/smp.h> 1568ea0e0bSAndrew Jones 1668ea0e0bSAndrew Jones cpumask_t cpu_present_mask; 1768ea0e0bSAndrew Jones cpumask_t cpu_online_mask; 18*543ce33cSAndrew Jones cpumask_t cpu_halted_mask; 1968ea0e0bSAndrew Jones struct secondary_data secondary_data; 2068ea0e0bSAndrew Jones 2168ea0e0bSAndrew Jones secondary_entry_fn secondary_cinit(void) 2268ea0e0bSAndrew Jones { 2368ea0e0bSAndrew Jones struct thread_info *ti = current_thread_info(); 2468ea0e0bSAndrew Jones secondary_entry_fn entry; 2568ea0e0bSAndrew Jones 2668ea0e0bSAndrew Jones thread_info_init(ti, 0); 271742c67aSAndrew Jones mmu_mark_enabled(ti->cpu); 2868ea0e0bSAndrew Jones 2968ea0e0bSAndrew Jones /* 3068ea0e0bSAndrew Jones * Save secondary_data.entry locally to avoid opening a race 3168ea0e0bSAndrew Jones * window between marking ourselves online and calling it. 3268ea0e0bSAndrew Jones */ 3368ea0e0bSAndrew Jones entry = secondary_data.entry; 3468ea0e0bSAndrew Jones set_cpu_online(ti->cpu, true); 3568ea0e0bSAndrew Jones sev(); 3668ea0e0bSAndrew Jones 3768ea0e0bSAndrew Jones /* 3868ea0e0bSAndrew Jones * Return to the assembly stub, allowing entry to be called 3968ea0e0bSAndrew Jones * from there with an empty stack. 4068ea0e0bSAndrew Jones */ 4168ea0e0bSAndrew Jones return entry; 4268ea0e0bSAndrew Jones } 4368ea0e0bSAndrew Jones 4468ea0e0bSAndrew Jones void smp_boot_secondary(int cpu, secondary_entry_fn entry) 4568ea0e0bSAndrew Jones { 4618ab6cadSAndrew Jones int ret; 4768ea0e0bSAndrew Jones 48632f935cSAndrew Jones secondary_data.stack = thread_stack_alloc(); 4968ea0e0bSAndrew Jones secondary_data.entry = entry; 501742c67aSAndrew Jones mmu_mark_disabled(cpu); 5118ab6cadSAndrew Jones ret = cpu_psci_cpu_boot(cpu); 5218ab6cadSAndrew Jones assert(ret == 0); 5368ea0e0bSAndrew Jones 5468ea0e0bSAndrew Jones while (!cpu_online(cpu)) 5568ea0e0bSAndrew Jones wfe(); 5668ea0e0bSAndrew Jones } 57*543ce33cSAndrew Jones 58*543ce33cSAndrew Jones void secondary_halt(void) 59*543ce33cSAndrew Jones { 60*543ce33cSAndrew Jones struct thread_info *ti = current_thread_info(); 61*543ce33cSAndrew Jones 62*543ce33cSAndrew Jones cpumask_set_cpu(ti->cpu, &cpu_halted_mask); 63*543ce33cSAndrew Jones halt(); 64*543ce33cSAndrew Jones } 65*543ce33cSAndrew Jones 66*543ce33cSAndrew Jones void smp_run(void (*func)(void)) 67*543ce33cSAndrew Jones { 68*543ce33cSAndrew Jones int cpu; 69*543ce33cSAndrew Jones 70*543ce33cSAndrew Jones for_each_present_cpu(cpu) { 71*543ce33cSAndrew Jones if (cpu == 0) 72*543ce33cSAndrew Jones continue; 73*543ce33cSAndrew Jones smp_boot_secondary(cpu, func); 74*543ce33cSAndrew Jones } 75*543ce33cSAndrew Jones func(); 76*543ce33cSAndrew Jones 77*543ce33cSAndrew Jones cpumask_set_cpu(0, &cpu_halted_mask); 78*543ce33cSAndrew Jones while (!cpumask_full(&cpu_halted_mask)) 79*543ce33cSAndrew Jones cpu_relax(); 80*543ce33cSAndrew Jones cpumask_clear_cpu(0, &cpu_halted_mask); 81*543ce33cSAndrew Jones } 82