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> 120b27f391SAndrew Jones #include <asm/spinlock.h> 13b2d54669SAndrew Jones 14b2d54669SAndrew Jones bool cpu0_calls_idle; 15b2d54669SAndrew Jones 16b2d54669SAndrew Jones struct on_cpu_info { 17b2d54669SAndrew Jones void (*func)(void *data); 18b2d54669SAndrew Jones void *data; 19b2d54669SAndrew Jones cpumask_t waiters; 20b2d54669SAndrew Jones }; 21b2d54669SAndrew Jones static struct on_cpu_info on_cpu_info[NR_CPUS]; 220b27f391SAndrew Jones static struct spinlock lock; 23b2d54669SAndrew Jones 24b2d54669SAndrew Jones static void __deadlock_check(int cpu, const cpumask_t *waiters, bool *found) 25b2d54669SAndrew Jones { 26b2d54669SAndrew Jones int i; 27b2d54669SAndrew Jones 28b2d54669SAndrew Jones for_each_cpu(i, waiters) { 29b2d54669SAndrew Jones if (i == cpu) { 30b2d54669SAndrew Jones printf("CPU%d", cpu); 31b2d54669SAndrew Jones *found = true; 32b2d54669SAndrew Jones return; 33b2d54669SAndrew Jones } 34b2d54669SAndrew Jones __deadlock_check(cpu, &on_cpu_info[i].waiters, found); 35b2d54669SAndrew Jones if (*found) { 36b2d54669SAndrew Jones printf(" <=> CPU%d", i); 37b2d54669SAndrew Jones return; 38b2d54669SAndrew Jones } 39b2d54669SAndrew Jones } 40b2d54669SAndrew Jones } 41b2d54669SAndrew Jones 42b2d54669SAndrew Jones static void deadlock_check(int me, int cpu) 43b2d54669SAndrew Jones { 44b2d54669SAndrew Jones bool found = false; 45b2d54669SAndrew Jones 46b2d54669SAndrew Jones __deadlock_check(cpu, &on_cpu_info[me].waiters, &found); 47b2d54669SAndrew Jones if (found) { 48b2d54669SAndrew Jones printf(" <=> CPU%d deadlock detectd\n", me); 49b2d54669SAndrew Jones assert(0); 50b2d54669SAndrew Jones } 51b2d54669SAndrew Jones } 52b2d54669SAndrew Jones 53b2d54669SAndrew Jones static void cpu_wait(int cpu) 54b2d54669SAndrew Jones { 55b2d54669SAndrew Jones int me = smp_processor_id(); 56b2d54669SAndrew Jones 57b2d54669SAndrew Jones if (cpu == me) 58b2d54669SAndrew Jones return; 59b2d54669SAndrew Jones 60b2d54669SAndrew Jones cpumask_set_cpu(me, &on_cpu_info[cpu].waiters); 61b2d54669SAndrew Jones deadlock_check(me, cpu); 62b2d54669SAndrew Jones while (!cpu_idle(cpu)) 63b2d54669SAndrew Jones smp_wait_for_event(); 64b2d54669SAndrew Jones cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters); 65b2d54669SAndrew Jones } 66b2d54669SAndrew Jones 67b2d54669SAndrew Jones void do_idle(void) 68b2d54669SAndrew Jones { 69b2d54669SAndrew Jones int cpu = smp_processor_id(); 70b2d54669SAndrew Jones 71b2d54669SAndrew Jones if (cpu == 0) 72b2d54669SAndrew Jones cpu0_calls_idle = true; 73b2d54669SAndrew Jones 740b27f391SAndrew Jones for (;;) { 75b2d54669SAndrew Jones set_cpu_idle(cpu, true); 76b2d54669SAndrew Jones smp_send_event(); 77b2d54669SAndrew Jones 78b2d54669SAndrew Jones while (cpu_idle(cpu)) 79b2d54669SAndrew Jones smp_wait_for_event(); 80b2d54669SAndrew Jones smp_rmb(); 81b2d54669SAndrew Jones on_cpu_info[cpu].func(on_cpu_info[cpu].data); 82*2491edacSAndrew Jones smp_wmb(); /* pairs with the smp_rmb() in on_cpu() and on_cpumask() */ 83b2d54669SAndrew Jones } 84b2d54669SAndrew Jones } 85b2d54669SAndrew Jones 86b2d54669SAndrew Jones void on_cpu_async(int cpu, void (*func)(void *data), void *data) 87b2d54669SAndrew Jones { 88b2d54669SAndrew Jones if (cpu == smp_processor_id()) { 89b2d54669SAndrew Jones func(data); 90b2d54669SAndrew Jones return; 91b2d54669SAndrew Jones } 92b2d54669SAndrew Jones 93b2d54669SAndrew Jones assert_msg(cpu != 0 || cpu0_calls_idle, "Waiting on CPU0, which is unlikely to idle. " 94b2d54669SAndrew Jones "If this is intended set cpu0_calls_idle=1"); 95b2d54669SAndrew Jones 96b2d54669SAndrew Jones smp_boot_secondary_nofail(cpu, do_idle); 97b2d54669SAndrew Jones 98b2d54669SAndrew Jones for (;;) { 99b2d54669SAndrew Jones cpu_wait(cpu); 1000b27f391SAndrew Jones spin_lock(&lock); 1010b27f391SAndrew Jones if (cpu_idle(cpu)) 102b2d54669SAndrew Jones break; 1030b27f391SAndrew Jones spin_unlock(&lock); 104b2d54669SAndrew Jones } 105b2d54669SAndrew Jones 106b2d54669SAndrew Jones on_cpu_info[cpu].func = func; 107b2d54669SAndrew Jones on_cpu_info[cpu].data = data; 1080b27f391SAndrew Jones smp_wmb(); 109b2d54669SAndrew Jones set_cpu_idle(cpu, false); 1100b27f391SAndrew Jones spin_unlock(&lock); 111b2d54669SAndrew Jones smp_send_event(); 112b2d54669SAndrew Jones } 113b2d54669SAndrew Jones 114d012cfd5SAndrew Jones void on_cpumask_async(const cpumask_t *mask, void (*func)(void *data), void *data) 115d012cfd5SAndrew Jones { 116d012cfd5SAndrew Jones int cpu, me = smp_processor_id(); 117d012cfd5SAndrew Jones 118d012cfd5SAndrew Jones for_each_cpu(cpu, mask) { 119d012cfd5SAndrew Jones if (cpu == me) 120d012cfd5SAndrew Jones continue; 121d012cfd5SAndrew Jones on_cpu_async(cpu, func, data); 122d012cfd5SAndrew Jones } 123d012cfd5SAndrew Jones if (cpumask_test_cpu(me, mask)) 124d012cfd5SAndrew Jones func(data); 125d012cfd5SAndrew Jones } 126d012cfd5SAndrew Jones 127d012cfd5SAndrew Jones void on_cpumask(const cpumask_t *mask, void (*func)(void *data), void *data) 128d012cfd5SAndrew Jones { 129d012cfd5SAndrew Jones int cpu, me = smp_processor_id(); 130d012cfd5SAndrew Jones 131d012cfd5SAndrew Jones for_each_cpu(cpu, mask) { 132d012cfd5SAndrew Jones if (cpu == me) 133d012cfd5SAndrew Jones continue; 134d012cfd5SAndrew Jones on_cpu_async(cpu, func, data); 135d012cfd5SAndrew Jones } 136d012cfd5SAndrew Jones if (cpumask_test_cpu(me, mask)) 137d012cfd5SAndrew Jones func(data); 138d012cfd5SAndrew Jones 139d012cfd5SAndrew Jones for_each_cpu(cpu, mask) { 140d012cfd5SAndrew Jones if (cpu == me) 141d012cfd5SAndrew Jones continue; 142d012cfd5SAndrew Jones cpumask_set_cpu(me, &on_cpu_info[cpu].waiters); 143d012cfd5SAndrew Jones deadlock_check(me, cpu); 144d012cfd5SAndrew Jones } 145d012cfd5SAndrew Jones while (cpumask_weight(&cpu_idle_mask) < nr_cpus - 1) 146d012cfd5SAndrew Jones smp_wait_for_event(); 147d012cfd5SAndrew Jones for_each_cpu(cpu, mask) 148d012cfd5SAndrew Jones cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters); 149*2491edacSAndrew Jones smp_rmb(); /* pairs with the smp_wmb() in do_idle() */ 150d012cfd5SAndrew Jones } 151d012cfd5SAndrew Jones 152b2d54669SAndrew Jones void on_cpu(int cpu, void (*func)(void *data), void *data) 153b2d54669SAndrew Jones { 154b2d54669SAndrew Jones on_cpu_async(cpu, func, data); 155b2d54669SAndrew Jones cpu_wait(cpu); 156*2491edacSAndrew Jones smp_rmb(); /* pairs with the smp_wmb() in do_idle() */ 157b2d54669SAndrew Jones } 158b2d54669SAndrew Jones 159b2d54669SAndrew Jones void on_cpus(void (*func)(void *data), void *data) 160b2d54669SAndrew Jones { 161d012cfd5SAndrew Jones on_cpumask(&cpu_present_mask, func, data); 162b2d54669SAndrew Jones } 163