1*ffdb5976SRusty Russell /* Copyright 2008, 2005 Rusty Russell [email protected] IBM Corporation. 2e5582ca2SRusty Russell * GPL v2 and any later version. 3e5582ca2SRusty Russell */ 41da177e4SLinus Torvalds #include <linux/cpu.h> 51da177e4SLinus Torvalds #include <linux/err.h> 6ee527cd3SPrarit Bhargava #include <linux/kthread.h> 7ee527cd3SPrarit Bhargava #include <linux/module.h> 8ee527cd3SPrarit Bhargava #include <linux/sched.h> 9ee527cd3SPrarit Bhargava #include <linux/stop_machine.h> 101da177e4SLinus Torvalds #include <linux/syscalls.h> 11a12bb444SBenjamin Herrenschmidt #include <linux/interrupt.h> 12a12bb444SBenjamin Herrenschmidt 131da177e4SLinus Torvalds #include <asm/atomic.h> 141da177e4SLinus Torvalds #include <asm/uaccess.h> 151da177e4SLinus Torvalds 16*ffdb5976SRusty Russell /* This controls the threads on each CPU. */ 171da177e4SLinus Torvalds enum stopmachine_state { 18*ffdb5976SRusty Russell /* Dummy starting state for thread. */ 19*ffdb5976SRusty Russell STOPMACHINE_NONE, 20*ffdb5976SRusty Russell /* Awaiting everyone to be scheduled. */ 211da177e4SLinus Torvalds STOPMACHINE_PREPARE, 22*ffdb5976SRusty Russell /* Disable interrupts. */ 231da177e4SLinus Torvalds STOPMACHINE_DISABLE_IRQ, 24*ffdb5976SRusty Russell /* Run the function */ 255c2aed62SJason Baron STOPMACHINE_RUN, 26*ffdb5976SRusty Russell /* Exit */ 271da177e4SLinus Torvalds STOPMACHINE_EXIT, 281da177e4SLinus Torvalds }; 29*ffdb5976SRusty Russell static enum stopmachine_state state; 301da177e4SLinus Torvalds 315c2aed62SJason Baron struct stop_machine_data { 325c2aed62SJason Baron int (*fn)(void *); 335c2aed62SJason Baron void *data; 34*ffdb5976SRusty Russell int fnret; 35*ffdb5976SRusty Russell }; 365c2aed62SJason Baron 37*ffdb5976SRusty Russell /* Like num_online_cpus(), but hotplug cpu uses us, so we need this. */ 38*ffdb5976SRusty Russell static unsigned int num_threads; 39*ffdb5976SRusty Russell static atomic_t thread_ack; 40*ffdb5976SRusty Russell static struct completion finished; 41*ffdb5976SRusty Russell static DEFINE_MUTEX(lock); 421da177e4SLinus Torvalds 43*ffdb5976SRusty Russell static void set_state(enum stopmachine_state newstate) 441da177e4SLinus Torvalds { 45*ffdb5976SRusty Russell /* Reset ack counter. */ 46*ffdb5976SRusty Russell atomic_set(&thread_ack, num_threads); 47*ffdb5976SRusty Russell smp_wmb(); 48*ffdb5976SRusty Russell state = newstate; 49*ffdb5976SRusty Russell } 501da177e4SLinus Torvalds 51*ffdb5976SRusty Russell /* Last one to ack a state moves to the next state. */ 52*ffdb5976SRusty Russell static void ack_state(void) 53*ffdb5976SRusty Russell { 54*ffdb5976SRusty Russell if (atomic_dec_and_test(&thread_ack)) { 55*ffdb5976SRusty Russell /* If we're the last one to ack the EXIT, we're finished. */ 56*ffdb5976SRusty Russell if (state == STOPMACHINE_EXIT) 57*ffdb5976SRusty Russell complete(&finished); 58*ffdb5976SRusty Russell else 59*ffdb5976SRusty Russell set_state(state + 1); 60*ffdb5976SRusty Russell } 61*ffdb5976SRusty Russell } 62d8cb7c1dSAndrew Morton 63*ffdb5976SRusty Russell /* This is the actual thread which stops the CPU. It exits by itself rather 64*ffdb5976SRusty Russell * than waiting for kthread_stop(), because it's easier for hotplug CPU. */ 65*ffdb5976SRusty Russell static int stop_cpu(struct stop_machine_data *smdata) 66*ffdb5976SRusty Russell { 67*ffdb5976SRusty Russell enum stopmachine_state curstate = STOPMACHINE_NONE; 68*ffdb5976SRusty Russell int uninitialized_var(ret); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* Simple state machine */ 71*ffdb5976SRusty Russell do { 72*ffdb5976SRusty Russell /* Chill out and ensure we re-read stopmachine_state. */ 73*ffdb5976SRusty Russell cpu_relax(); 74*ffdb5976SRusty Russell if (state != curstate) { 75*ffdb5976SRusty Russell curstate = state; 76*ffdb5976SRusty Russell switch (curstate) { 77*ffdb5976SRusty Russell case STOPMACHINE_DISABLE_IRQ: 781da177e4SLinus Torvalds local_irq_disable(); 79a12bb444SBenjamin Herrenschmidt hard_irq_disable(); 80*ffdb5976SRusty Russell break; 81*ffdb5976SRusty Russell case STOPMACHINE_RUN: 82*ffdb5976SRusty Russell /* |= allows error detection if functions on 83*ffdb5976SRusty Russell * multiple CPUs. */ 84*ffdb5976SRusty Russell smdata->fnret |= smdata->fn(smdata->data); 85*ffdb5976SRusty Russell break; 86*ffdb5976SRusty Russell default: 87*ffdb5976SRusty Russell break; 881da177e4SLinus Torvalds } 89*ffdb5976SRusty Russell ack_state(); 901da177e4SLinus Torvalds } 91*ffdb5976SRusty Russell } while (curstate != STOPMACHINE_EXIT); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds local_irq_enable(); 94*ffdb5976SRusty Russell do_exit(0); 95*ffdb5976SRusty Russell } 961da177e4SLinus Torvalds 97*ffdb5976SRusty Russell /* Callback for CPUs which aren't supposed to do anything. */ 98*ffdb5976SRusty Russell static int chill(void *unused) 99*ffdb5976SRusty Russell { 1001da177e4SLinus Torvalds return 0; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 103*ffdb5976SRusty Russell int __stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) 1041da177e4SLinus Torvalds { 105*ffdb5976SRusty Russell int i, err; 106*ffdb5976SRusty Russell struct stop_machine_data active, idle; 107*ffdb5976SRusty Russell struct task_struct **threads; 1081da177e4SLinus Torvalds 109*ffdb5976SRusty Russell active.fn = fn; 110*ffdb5976SRusty Russell active.data = data; 111*ffdb5976SRusty Russell active.fnret = 0; 112*ffdb5976SRusty Russell idle.fn = chill; 113*ffdb5976SRusty Russell idle.data = NULL; 1141da177e4SLinus Torvalds 115*ffdb5976SRusty Russell /* If they don't care which cpu fn runs on, just pick one. */ 116*ffdb5976SRusty Russell if (cpu == NR_CPUS) 117*ffdb5976SRusty Russell cpu = any_online_cpu(cpu_online_map); 118*ffdb5976SRusty Russell 119*ffdb5976SRusty Russell /* This could be too big for stack on large machines. */ 120*ffdb5976SRusty Russell threads = kcalloc(NR_CPUS, sizeof(threads[0]), GFP_KERNEL); 121*ffdb5976SRusty Russell if (!threads) 122*ffdb5976SRusty Russell return -ENOMEM; 123*ffdb5976SRusty Russell 124*ffdb5976SRusty Russell /* Set up initial state. */ 125*ffdb5976SRusty Russell mutex_lock(&lock); 126*ffdb5976SRusty Russell init_completion(&finished); 127*ffdb5976SRusty Russell num_threads = num_online_cpus(); 128*ffdb5976SRusty Russell set_state(STOPMACHINE_PREPARE); 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds for_each_online_cpu(i) { 131*ffdb5976SRusty Russell struct stop_machine_data *smdata; 13285653af7SSatoru Takeuchi struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; 13385653af7SSatoru Takeuchi 134*ffdb5976SRusty Russell if (cpu == ALL_CPUS || i == cpu) 135*ffdb5976SRusty Russell smdata = &active; 136*ffdb5976SRusty Russell else 137*ffdb5976SRusty Russell smdata = &idle; 138*ffdb5976SRusty Russell 139*ffdb5976SRusty Russell threads[i] = kthread_create((void *)stop_cpu, smdata, "kstop%u", 140*ffdb5976SRusty Russell i); 141*ffdb5976SRusty Russell if (IS_ERR(threads[i])) { 142*ffdb5976SRusty Russell err = PTR_ERR(threads[i]); 143*ffdb5976SRusty Russell threads[i] = NULL; 144*ffdb5976SRusty Russell goto kill_threads; 1451da177e4SLinus Torvalds } 146*ffdb5976SRusty Russell 147*ffdb5976SRusty Russell /* Place it onto correct cpu. */ 148*ffdb5976SRusty Russell kthread_bind(threads[i], i); 149*ffdb5976SRusty Russell 150*ffdb5976SRusty Russell /* Make it highest prio. */ 151*ffdb5976SRusty Russell if (sched_setscheduler_nocheck(threads[i], SCHED_FIFO, ¶m)) 152*ffdb5976SRusty Russell BUG(); 153*ffdb5976SRusty Russell } 154*ffdb5976SRusty Russell 155*ffdb5976SRusty Russell /* We've created all the threads. Wake them all: hold this CPU so one 156*ffdb5976SRusty Russell * doesn't hit this CPU until we're ready. */ 157*ffdb5976SRusty Russell cpu = get_cpu(); 158*ffdb5976SRusty Russell for_each_online_cpu(i) 159*ffdb5976SRusty Russell wake_up_process(threads[i]); 160*ffdb5976SRusty Russell 161*ffdb5976SRusty Russell /* This will release the thread on our CPU. */ 162*ffdb5976SRusty Russell put_cpu(); 163*ffdb5976SRusty Russell wait_for_completion(&finished); 164*ffdb5976SRusty Russell mutex_unlock(&lock); 165*ffdb5976SRusty Russell 166*ffdb5976SRusty Russell kfree(threads); 167*ffdb5976SRusty Russell 168*ffdb5976SRusty Russell return active.fnret; 169*ffdb5976SRusty Russell 170*ffdb5976SRusty Russell kill_threads: 171*ffdb5976SRusty Russell for_each_online_cpu(i) 172*ffdb5976SRusty Russell if (threads[i]) 173*ffdb5976SRusty Russell kthread_stop(threads[i]); 174*ffdb5976SRusty Russell mutex_unlock(&lock); 175*ffdb5976SRusty Russell 176*ffdb5976SRusty Russell kfree(threads); 177*ffdb5976SRusty Russell return err; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds int ret; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds /* No CPUs can come up or down during this. */ 18586ef5c9aSGautham R Shenoy get_online_cpus(); 186*ffdb5976SRusty Russell ret = __stop_machine_run(fn, data, cpu); 18786ef5c9aSGautham R Shenoy put_online_cpus(); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds return ret; 1901da177e4SLinus Torvalds } 191ee527cd3SPrarit Bhargava EXPORT_SYMBOL_GPL(stop_machine_run); 192