1b2d54669SAndrew Jones // SPDX-License-Identifier: GPL-2.0-only 2b2d54669SAndrew Jones /* 3b2d54669SAndrew Jones * on_cpus() support based on cpumasks. 4b2d54669SAndrew Jones * 5b2d54669SAndrew Jones * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com> 6b2d54669SAndrew Jones */ 7b2d54669SAndrew Jones #include <libcflat.h> 8b2d54669SAndrew Jones #include <cpumask.h> 9b2d54669SAndrew Jones #include <on-cpus.h> 10b2d54669SAndrew Jones #include <asm/barrier.h> 11b2d54669SAndrew Jones #include <asm/smp.h> 12b2d54669SAndrew Jones 13b2d54669SAndrew Jones bool cpu0_calls_idle; 14b2d54669SAndrew Jones 15b2d54669SAndrew Jones struct on_cpu_info { 16b2d54669SAndrew Jones void (*func)(void *data); 17b2d54669SAndrew Jones void *data; 18b2d54669SAndrew Jones cpumask_t waiters; 19b2d54669SAndrew Jones }; 20b2d54669SAndrew Jones static struct on_cpu_info on_cpu_info[NR_CPUS]; 21b2d54669SAndrew Jones static cpumask_t on_cpu_info_lock; 22b2d54669SAndrew Jones 23b2d54669SAndrew Jones static bool get_on_cpu_info(int cpu) 24b2d54669SAndrew Jones { 25b2d54669SAndrew Jones return !cpumask_test_and_set_cpu(cpu, &on_cpu_info_lock); 26b2d54669SAndrew Jones } 27b2d54669SAndrew Jones 28b2d54669SAndrew Jones static void put_on_cpu_info(int cpu) 29b2d54669SAndrew Jones { 30b2d54669SAndrew Jones int ret = cpumask_test_and_clear_cpu(cpu, &on_cpu_info_lock); 31b2d54669SAndrew Jones assert(ret); 32b2d54669SAndrew Jones } 33b2d54669SAndrew Jones 34b2d54669SAndrew Jones static void __deadlock_check(int cpu, const cpumask_t *waiters, bool *found) 35b2d54669SAndrew Jones { 36b2d54669SAndrew Jones int i; 37b2d54669SAndrew Jones 38b2d54669SAndrew Jones for_each_cpu(i, waiters) { 39b2d54669SAndrew Jones if (i == cpu) { 40b2d54669SAndrew Jones printf("CPU%d", cpu); 41b2d54669SAndrew Jones *found = true; 42b2d54669SAndrew Jones return; 43b2d54669SAndrew Jones } 44b2d54669SAndrew Jones __deadlock_check(cpu, &on_cpu_info[i].waiters, found); 45b2d54669SAndrew Jones if (*found) { 46b2d54669SAndrew Jones printf(" <=> CPU%d", i); 47b2d54669SAndrew Jones return; 48b2d54669SAndrew Jones } 49b2d54669SAndrew Jones } 50b2d54669SAndrew Jones } 51b2d54669SAndrew Jones 52b2d54669SAndrew Jones static void deadlock_check(int me, int cpu) 53b2d54669SAndrew Jones { 54b2d54669SAndrew Jones bool found = false; 55b2d54669SAndrew Jones 56b2d54669SAndrew Jones __deadlock_check(cpu, &on_cpu_info[me].waiters, &found); 57b2d54669SAndrew Jones if (found) { 58b2d54669SAndrew Jones printf(" <=> CPU%d deadlock detectd\n", me); 59b2d54669SAndrew Jones assert(0); 60b2d54669SAndrew Jones } 61b2d54669SAndrew Jones } 62b2d54669SAndrew Jones 63b2d54669SAndrew Jones static void cpu_wait(int cpu) 64b2d54669SAndrew Jones { 65b2d54669SAndrew Jones int me = smp_processor_id(); 66b2d54669SAndrew Jones 67b2d54669SAndrew Jones if (cpu == me) 68b2d54669SAndrew Jones return; 69b2d54669SAndrew Jones 70b2d54669SAndrew Jones cpumask_set_cpu(me, &on_cpu_info[cpu].waiters); 71b2d54669SAndrew Jones deadlock_check(me, cpu); 72b2d54669SAndrew Jones while (!cpu_idle(cpu)) 73b2d54669SAndrew Jones smp_wait_for_event(); 74b2d54669SAndrew Jones cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters); 75b2d54669SAndrew Jones } 76b2d54669SAndrew Jones 77b2d54669SAndrew Jones void do_idle(void) 78b2d54669SAndrew Jones { 79b2d54669SAndrew Jones int cpu = smp_processor_id(); 80b2d54669SAndrew Jones 81b2d54669SAndrew Jones if (cpu == 0) 82b2d54669SAndrew Jones cpu0_calls_idle = true; 83b2d54669SAndrew Jones 84b2d54669SAndrew Jones set_cpu_idle(cpu, true); 85b2d54669SAndrew Jones smp_send_event(); 86b2d54669SAndrew Jones 87b2d54669SAndrew Jones for (;;) { 88b2d54669SAndrew Jones while (cpu_idle(cpu)) 89b2d54669SAndrew Jones smp_wait_for_event(); 90b2d54669SAndrew Jones smp_rmb(); 91b2d54669SAndrew Jones on_cpu_info[cpu].func(on_cpu_info[cpu].data); 92b2d54669SAndrew Jones on_cpu_info[cpu].func = NULL; 93b2d54669SAndrew Jones smp_wmb(); 94b2d54669SAndrew Jones set_cpu_idle(cpu, true); 95b2d54669SAndrew Jones smp_send_event(); 96b2d54669SAndrew Jones } 97b2d54669SAndrew Jones } 98b2d54669SAndrew Jones 99b2d54669SAndrew Jones void on_cpu_async(int cpu, void (*func)(void *data), void *data) 100b2d54669SAndrew Jones { 101b2d54669SAndrew Jones if (cpu == smp_processor_id()) { 102b2d54669SAndrew Jones func(data); 103b2d54669SAndrew Jones return; 104b2d54669SAndrew Jones } 105b2d54669SAndrew Jones 106b2d54669SAndrew Jones assert_msg(cpu != 0 || cpu0_calls_idle, "Waiting on CPU0, which is unlikely to idle. " 107b2d54669SAndrew Jones "If this is intended set cpu0_calls_idle=1"); 108b2d54669SAndrew Jones 109b2d54669SAndrew Jones smp_boot_secondary_nofail(cpu, do_idle); 110b2d54669SAndrew Jones 111b2d54669SAndrew Jones for (;;) { 112b2d54669SAndrew Jones cpu_wait(cpu); 113b2d54669SAndrew Jones if (get_on_cpu_info(cpu)) { 114b2d54669SAndrew Jones if ((volatile void *)on_cpu_info[cpu].func == NULL) 115b2d54669SAndrew Jones break; 116b2d54669SAndrew Jones put_on_cpu_info(cpu); 117b2d54669SAndrew Jones } 118b2d54669SAndrew Jones } 119b2d54669SAndrew Jones 120b2d54669SAndrew Jones on_cpu_info[cpu].func = func; 121b2d54669SAndrew Jones on_cpu_info[cpu].data = data; 122b2d54669SAndrew Jones set_cpu_idle(cpu, false); 123b2d54669SAndrew Jones put_on_cpu_info(cpu); 124b2d54669SAndrew Jones smp_send_event(); 125b2d54669SAndrew Jones } 126b2d54669SAndrew Jones 127*d012cfd5SAndrew Jones void on_cpumask_async(const cpumask_t *mask, void (*func)(void *data), void *data) 128*d012cfd5SAndrew Jones { 129*d012cfd5SAndrew Jones int cpu, me = smp_processor_id(); 130*d012cfd5SAndrew Jones 131*d012cfd5SAndrew Jones for_each_cpu(cpu, mask) { 132*d012cfd5SAndrew Jones if (cpu == me) 133*d012cfd5SAndrew Jones continue; 134*d012cfd5SAndrew Jones on_cpu_async(cpu, func, data); 135*d012cfd5SAndrew Jones } 136*d012cfd5SAndrew Jones if (cpumask_test_cpu(me, mask)) 137*d012cfd5SAndrew Jones func(data); 138*d012cfd5SAndrew Jones } 139*d012cfd5SAndrew Jones 140*d012cfd5SAndrew Jones void on_cpumask(const cpumask_t *mask, void (*func)(void *data), void *data) 141*d012cfd5SAndrew Jones { 142*d012cfd5SAndrew Jones int cpu, me = smp_processor_id(); 143*d012cfd5SAndrew Jones 144*d012cfd5SAndrew Jones for_each_cpu(cpu, mask) { 145*d012cfd5SAndrew Jones if (cpu == me) 146*d012cfd5SAndrew Jones continue; 147*d012cfd5SAndrew Jones on_cpu_async(cpu, func, data); 148*d012cfd5SAndrew Jones } 149*d012cfd5SAndrew Jones if (cpumask_test_cpu(me, mask)) 150*d012cfd5SAndrew Jones func(data); 151*d012cfd5SAndrew Jones 152*d012cfd5SAndrew Jones for_each_cpu(cpu, mask) { 153*d012cfd5SAndrew Jones if (cpu == me) 154*d012cfd5SAndrew Jones continue; 155*d012cfd5SAndrew Jones cpumask_set_cpu(me, &on_cpu_info[cpu].waiters); 156*d012cfd5SAndrew Jones deadlock_check(me, cpu); 157*d012cfd5SAndrew Jones } 158*d012cfd5SAndrew Jones while (cpumask_weight(&cpu_idle_mask) < nr_cpus - 1) 159*d012cfd5SAndrew Jones smp_wait_for_event(); 160*d012cfd5SAndrew Jones for_each_cpu(cpu, mask) 161*d012cfd5SAndrew Jones cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters); 162*d012cfd5SAndrew Jones } 163*d012cfd5SAndrew Jones 164b2d54669SAndrew Jones void on_cpu(int cpu, void (*func)(void *data), void *data) 165b2d54669SAndrew Jones { 166b2d54669SAndrew Jones on_cpu_async(cpu, func, data); 167b2d54669SAndrew Jones cpu_wait(cpu); 168b2d54669SAndrew Jones } 169b2d54669SAndrew Jones 170b2d54669SAndrew Jones void on_cpus(void (*func)(void *data), void *data) 171b2d54669SAndrew Jones { 172*d012cfd5SAndrew Jones on_cpumask(&cpu_present_mask, func, data); 173b2d54669SAndrew Jones } 174