11da177e4SLinus Torvalds /* CPU control. 21da177e4SLinus Torvalds * (C) 2001, 2002, 2003, 2004 Rusty Russell 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This code is licenced under the GPL. 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds #include <linux/proc_fs.h> 71da177e4SLinus Torvalds #include <linux/smp.h> 81da177e4SLinus Torvalds #include <linux/init.h> 91da177e4SLinus Torvalds #include <linux/notifier.h> 101da177e4SLinus Torvalds #include <linux/sched.h> 111da177e4SLinus Torvalds #include <linux/unistd.h> 121da177e4SLinus Torvalds #include <linux/cpu.h> 131da177e4SLinus Torvalds #include <linux/module.h> 141da177e4SLinus Torvalds #include <linux/kthread.h> 151da177e4SLinus Torvalds #include <linux/stop_machine.h> 1681615b62SIngo Molnar #include <linux/mutex.h> 171da177e4SLinus Torvalds 1868f4f1ecSMax Krasnyansky /* 1968f4f1ecSMax Krasnyansky * Represents all cpu's present in the system 2068f4f1ecSMax Krasnyansky * In systems capable of hotplug, this map could dynamically grow 2168f4f1ecSMax Krasnyansky * as new cpu's are detected in the system via any platform specific 2268f4f1ecSMax Krasnyansky * method, such as ACPI for e.g. 2368f4f1ecSMax Krasnyansky */ 2468f4f1ecSMax Krasnyansky cpumask_t cpu_present_map __read_mostly; 2568f4f1ecSMax Krasnyansky EXPORT_SYMBOL(cpu_present_map); 2668f4f1ecSMax Krasnyansky 2768f4f1ecSMax Krasnyansky #ifndef CONFIG_SMP 2868f4f1ecSMax Krasnyansky 2968f4f1ecSMax Krasnyansky /* 3068f4f1ecSMax Krasnyansky * Represents all cpu's that are currently online. 3168f4f1ecSMax Krasnyansky */ 3268f4f1ecSMax Krasnyansky cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL; 3368f4f1ecSMax Krasnyansky EXPORT_SYMBOL(cpu_online_map); 3468f4f1ecSMax Krasnyansky 3568f4f1ecSMax Krasnyansky cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL; 3668f4f1ecSMax Krasnyansky EXPORT_SYMBOL(cpu_possible_map); 3768f4f1ecSMax Krasnyansky 3868f4f1ecSMax Krasnyansky #else /* CONFIG_SMP */ 3968f4f1ecSMax Krasnyansky 40d221938cSGautham R Shenoy /* Serializes the updates to cpu_online_map, cpu_present_map */ 41aa953877SLinus Torvalds static DEFINE_MUTEX(cpu_add_remove_lock); 421da177e4SLinus Torvalds 43bd5349cfSNeil Brown static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); 441da177e4SLinus Torvalds 45e3920fb4SRafael J. Wysocki /* If set, cpu_up and cpu_down will return -EBUSY and do nothing. 46e3920fb4SRafael J. Wysocki * Should always be manipulated under cpu_add_remove_lock 47e3920fb4SRafael J. Wysocki */ 48e3920fb4SRafael J. Wysocki static int cpu_hotplug_disabled; 49e3920fb4SRafael J. Wysocki 50d221938cSGautham R Shenoy static struct { 51d221938cSGautham R Shenoy struct task_struct *active_writer; 52d221938cSGautham R Shenoy struct mutex lock; /* Synchronizes accesses to refcount, */ 53d221938cSGautham R Shenoy /* 54d221938cSGautham R Shenoy * Also blocks the new readers during 55d221938cSGautham R Shenoy * an ongoing cpu hotplug operation. 56d221938cSGautham R Shenoy */ 57d221938cSGautham R Shenoy int refcount; 58d221938cSGautham R Shenoy } cpu_hotplug; 5990d45d17SAshok Raj 60d221938cSGautham R Shenoy void __init cpu_hotplug_init(void) 61d221938cSGautham R Shenoy { 62d221938cSGautham R Shenoy cpu_hotplug.active_writer = NULL; 63d221938cSGautham R Shenoy mutex_init(&cpu_hotplug.lock); 64d221938cSGautham R Shenoy cpu_hotplug.refcount = 0; 65d221938cSGautham R Shenoy } 66d221938cSGautham R Shenoy 67e761b772SMax Krasnyansky cpumask_t cpu_active_map; 68e761b772SMax Krasnyansky 69d221938cSGautham R Shenoy #ifdef CONFIG_HOTPLUG_CPU 70a9d9baa1SAshok Raj 7186ef5c9aSGautham R Shenoy void get_online_cpus(void) 72a9d9baa1SAshok Raj { 73d221938cSGautham R Shenoy might_sleep(); 74d221938cSGautham R Shenoy if (cpu_hotplug.active_writer == current) 75aa953877SLinus Torvalds return; 76d221938cSGautham R Shenoy mutex_lock(&cpu_hotplug.lock); 77d221938cSGautham R Shenoy cpu_hotplug.refcount++; 78d221938cSGautham R Shenoy mutex_unlock(&cpu_hotplug.lock); 79d221938cSGautham R Shenoy 80a9d9baa1SAshok Raj } 8186ef5c9aSGautham R Shenoy EXPORT_SYMBOL_GPL(get_online_cpus); 82a9d9baa1SAshok Raj 8386ef5c9aSGautham R Shenoy void put_online_cpus(void) 84a9d9baa1SAshok Raj { 85d221938cSGautham R Shenoy if (cpu_hotplug.active_writer == current) 86aa953877SLinus Torvalds return; 87d221938cSGautham R Shenoy mutex_lock(&cpu_hotplug.lock); 88d2ba7e2aSOleg Nesterov if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer)) 89d2ba7e2aSOleg Nesterov wake_up_process(cpu_hotplug.active_writer); 90d221938cSGautham R Shenoy mutex_unlock(&cpu_hotplug.lock); 91d221938cSGautham R Shenoy 92a9d9baa1SAshok Raj } 9386ef5c9aSGautham R Shenoy EXPORT_SYMBOL_GPL(put_online_cpus); 94a9d9baa1SAshok Raj 95a9d9baa1SAshok Raj #endif /* CONFIG_HOTPLUG_CPU */ 9690d45d17SAshok Raj 97d221938cSGautham R Shenoy /* 98d221938cSGautham R Shenoy * The following two API's must be used when attempting 99d221938cSGautham R Shenoy * to serialize the updates to cpu_online_map, cpu_present_map. 100d221938cSGautham R Shenoy */ 101d221938cSGautham R Shenoy void cpu_maps_update_begin(void) 102d221938cSGautham R Shenoy { 103d221938cSGautham R Shenoy mutex_lock(&cpu_add_remove_lock); 104d221938cSGautham R Shenoy } 105d221938cSGautham R Shenoy 106d221938cSGautham R Shenoy void cpu_maps_update_done(void) 107d221938cSGautham R Shenoy { 108d221938cSGautham R Shenoy mutex_unlock(&cpu_add_remove_lock); 109d221938cSGautham R Shenoy } 110d221938cSGautham R Shenoy 111d221938cSGautham R Shenoy /* 112d221938cSGautham R Shenoy * This ensures that the hotplug operation can begin only when the 113d221938cSGautham R Shenoy * refcount goes to zero. 114d221938cSGautham R Shenoy * 115d221938cSGautham R Shenoy * Note that during a cpu-hotplug operation, the new readers, if any, 116d221938cSGautham R Shenoy * will be blocked by the cpu_hotplug.lock 117d221938cSGautham R Shenoy * 118d2ba7e2aSOleg Nesterov * Since cpu_hotplug_begin() is always called after invoking 119d2ba7e2aSOleg Nesterov * cpu_maps_update_begin(), we can be sure that only one writer is active. 120d221938cSGautham R Shenoy * 121d221938cSGautham R Shenoy * Note that theoretically, there is a possibility of a livelock: 122d221938cSGautham R Shenoy * - Refcount goes to zero, last reader wakes up the sleeping 123d221938cSGautham R Shenoy * writer. 124d221938cSGautham R Shenoy * - Last reader unlocks the cpu_hotplug.lock. 125d221938cSGautham R Shenoy * - A new reader arrives at this moment, bumps up the refcount. 126d221938cSGautham R Shenoy * - The writer acquires the cpu_hotplug.lock finds the refcount 127d221938cSGautham R Shenoy * non zero and goes to sleep again. 128d221938cSGautham R Shenoy * 129d221938cSGautham R Shenoy * However, this is very difficult to achieve in practice since 13086ef5c9aSGautham R Shenoy * get_online_cpus() not an api which is called all that often. 131d221938cSGautham R Shenoy * 132d221938cSGautham R Shenoy */ 133d221938cSGautham R Shenoy static void cpu_hotplug_begin(void) 134d221938cSGautham R Shenoy { 135d221938cSGautham R Shenoy cpu_hotplug.active_writer = current; 136d2ba7e2aSOleg Nesterov 137d2ba7e2aSOleg Nesterov for (;;) { 138d2ba7e2aSOleg Nesterov mutex_lock(&cpu_hotplug.lock); 139d2ba7e2aSOleg Nesterov if (likely(!cpu_hotplug.refcount)) 140d2ba7e2aSOleg Nesterov break; 141d2ba7e2aSOleg Nesterov __set_current_state(TASK_UNINTERRUPTIBLE); 142d221938cSGautham R Shenoy mutex_unlock(&cpu_hotplug.lock); 143d221938cSGautham R Shenoy schedule(); 144d221938cSGautham R Shenoy } 145d221938cSGautham R Shenoy } 146d221938cSGautham R Shenoy 147d221938cSGautham R Shenoy static void cpu_hotplug_done(void) 148d221938cSGautham R Shenoy { 149d221938cSGautham R Shenoy cpu_hotplug.active_writer = NULL; 150d221938cSGautham R Shenoy mutex_unlock(&cpu_hotplug.lock); 151d221938cSGautham R Shenoy } 1521da177e4SLinus Torvalds /* Need to know about CPUs going up/down? */ 153f7b16c10SSam Ravnborg int __ref register_cpu_notifier(struct notifier_block *nb) 1541da177e4SLinus Torvalds { 155bd5349cfSNeil Brown int ret; 156d221938cSGautham R Shenoy cpu_maps_update_begin(); 157bd5349cfSNeil Brown ret = raw_notifier_chain_register(&cpu_chain, nb); 158d221938cSGautham R Shenoy cpu_maps_update_done(); 159bd5349cfSNeil Brown return ret; 1601da177e4SLinus Torvalds } 16165edc68cSChandra Seetharaman 16265edc68cSChandra Seetharaman #ifdef CONFIG_HOTPLUG_CPU 16365edc68cSChandra Seetharaman 1641da177e4SLinus Torvalds EXPORT_SYMBOL(register_cpu_notifier); 1651da177e4SLinus Torvalds 1669647155fSSam Ravnborg void __ref unregister_cpu_notifier(struct notifier_block *nb) 1671da177e4SLinus Torvalds { 168d221938cSGautham R Shenoy cpu_maps_update_begin(); 169bd5349cfSNeil Brown raw_notifier_chain_unregister(&cpu_chain, nb); 170d221938cSGautham R Shenoy cpu_maps_update_done(); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds EXPORT_SYMBOL(unregister_cpu_notifier); 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds static inline void check_for_tasks(int cpu) 1751da177e4SLinus Torvalds { 1761da177e4SLinus Torvalds struct task_struct *p; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds write_lock_irq(&tasklist_lock); 1791da177e4SLinus Torvalds for_each_process(p) { 1801da177e4SLinus Torvalds if (task_cpu(p) == cpu && 1811da177e4SLinus Torvalds (!cputime_eq(p->utime, cputime_zero) || 1821da177e4SLinus Torvalds !cputime_eq(p->stime, cputime_zero))) 1831da177e4SLinus Torvalds printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\ 184e7407dccSHeiko Carstens (state = %ld, flags = %x) \n", 185ba25f9dcSPavel Emelyanov p->comm, task_pid_nr(p), cpu, 186ba25f9dcSPavel Emelyanov p->state, p->flags); 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds write_unlock_irq(&tasklist_lock); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 191db912f96SAvi Kivity struct take_cpu_down_param { 192db912f96SAvi Kivity unsigned long mod; 193db912f96SAvi Kivity void *hcpu; 194db912f96SAvi Kivity }; 195db912f96SAvi Kivity 1961da177e4SLinus Torvalds /* Take this CPU down. */ 197514a20a5SSam Ravnborg static int __ref take_cpu_down(void *_param) 1981da177e4SLinus Torvalds { 199db912f96SAvi Kivity struct take_cpu_down_param *param = _param; 2001da177e4SLinus Torvalds int err; 2011da177e4SLinus Torvalds 202db912f96SAvi Kivity raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod, 203db912f96SAvi Kivity param->hcpu); 2041da177e4SLinus Torvalds /* Ensure this CPU doesn't handle any more interrupts. */ 2051da177e4SLinus Torvalds err = __cpu_disable(); 2061da177e4SLinus Torvalds if (err < 0) 207f3705136SZwane Mwaikambo return err; 208f3705136SZwane Mwaikambo 2091da177e4SLinus Torvalds /* Force idle task to run as soon as we yield: it should 2101da177e4SLinus Torvalds immediately notice cpu is offline and die quickly. */ 2111da177e4SLinus Torvalds sched_idle_next(); 212f3705136SZwane Mwaikambo return 0; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 215e3920fb4SRafael J. Wysocki /* Requires cpu_add_remove_lock to be held */ 216514a20a5SSam Ravnborg static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) 2171da177e4SLinus Torvalds { 218e7407dccSHeiko Carstens int err, nr_calls = 0; 2191da177e4SLinus Torvalds cpumask_t old_allowed, tmp; 220e7407dccSHeiko Carstens void *hcpu = (void *)(long)cpu; 2218bb78442SRafael J. Wysocki unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; 222db912f96SAvi Kivity struct take_cpu_down_param tcd_param = { 223db912f96SAvi Kivity .mod = mod, 224db912f96SAvi Kivity .hcpu = hcpu, 225db912f96SAvi Kivity }; 2261da177e4SLinus Torvalds 227e3920fb4SRafael J. Wysocki if (num_online_cpus() == 1) 228e3920fb4SRafael J. Wysocki return -EBUSY; 2291da177e4SLinus Torvalds 230e3920fb4SRafael J. Wysocki if (!cpu_online(cpu)) 231e3920fb4SRafael J. Wysocki return -EINVAL; 2321da177e4SLinus Torvalds 233d221938cSGautham R Shenoy cpu_hotplug_begin(); 2348bb78442SRafael J. Wysocki err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod, 235e7407dccSHeiko Carstens hcpu, -1, &nr_calls); 2361da177e4SLinus Torvalds if (err == NOTIFY_BAD) { 237a0d8cdb6SAkinobu Mita nr_calls--; 2388bb78442SRafael J. Wysocki __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, 2398bb78442SRafael J. Wysocki hcpu, nr_calls, NULL); 2401da177e4SLinus Torvalds printk("%s: attempt to take down CPU %u failed\n", 241af1f16d0SHarvey Harrison __func__, cpu); 242baaca49fSGautham R Shenoy err = -EINVAL; 243baaca49fSGautham R Shenoy goto out_release; 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds /* Ensure that we are not runnable on dying cpu */ 2471da177e4SLinus Torvalds old_allowed = current->cpus_allowed; 248f70316daSMike Travis cpus_setall(tmp); 2491da177e4SLinus Torvalds cpu_clear(cpu, tmp); 250f70316daSMike Travis set_cpus_allowed_ptr(current, &tmp); 251eeec4fadSRusty Russell tmp = cpumask_of_cpu(cpu); 2521da177e4SLinus Torvalds 253eeec4fadSRusty Russell err = __stop_machine(take_cpu_down, &tcd_param, &tmp); 25404321587SRusty Russell if (err) { 2551da177e4SLinus Torvalds /* CPU didn't die: tell everyone. Can't complain. */ 2568bb78442SRafael J. Wysocki if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, 257e7407dccSHeiko Carstens hcpu) == NOTIFY_BAD) 2581da177e4SLinus Torvalds BUG(); 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds goto out_allowed; 2611da177e4SLinus Torvalds } 26204321587SRusty Russell BUG_ON(cpu_online(cpu)); 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds /* Wait for it to sleep (leaving idle task). */ 2651da177e4SLinus Torvalds while (!idle_cpu(cpu)) 2661da177e4SLinus Torvalds yield(); 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds /* This actually kills the CPU. */ 2691da177e4SLinus Torvalds __cpu_die(cpu); 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds /* CPU is completely dead: tell everyone. Too late to complain. */ 2728bb78442SRafael J. Wysocki if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod, 2738bb78442SRafael J. Wysocki hcpu) == NOTIFY_BAD) 2741da177e4SLinus Torvalds BUG(); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds check_for_tasks(cpu); 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds out_allowed: 279f70316daSMike Travis set_cpus_allowed_ptr(current, &old_allowed); 280baaca49fSGautham R Shenoy out_release: 281d221938cSGautham R Shenoy cpu_hotplug_done(); 2823da1c84cSOleg Nesterov if (!err) { 2833da1c84cSOleg Nesterov if (raw_notifier_call_chain(&cpu_chain, CPU_POST_DEAD | mod, 2843da1c84cSOleg Nesterov hcpu) == NOTIFY_BAD) 2853da1c84cSOleg Nesterov BUG(); 2863da1c84cSOleg Nesterov } 287e3920fb4SRafael J. Wysocki return err; 288e3920fb4SRafael J. Wysocki } 289e3920fb4SRafael J. Wysocki 290514a20a5SSam Ravnborg int __ref cpu_down(unsigned int cpu) 291e3920fb4SRafael J. Wysocki { 292e3920fb4SRafael J. Wysocki int err = 0; 293e3920fb4SRafael J. Wysocki 294d221938cSGautham R Shenoy cpu_maps_update_begin(); 295e761b772SMax Krasnyansky 296e761b772SMax Krasnyansky if (cpu_hotplug_disabled) { 297e3920fb4SRafael J. Wysocki err = -EBUSY; 298e761b772SMax Krasnyansky goto out; 299e761b772SMax Krasnyansky } 300e761b772SMax Krasnyansky 301e761b772SMax Krasnyansky cpu_clear(cpu, cpu_active_map); 302e761b772SMax Krasnyansky 30339b0fad7SMax Krasnyansky /* 30439b0fad7SMax Krasnyansky * Make sure the all cpus did the reschedule and are not 30539b0fad7SMax Krasnyansky * using stale version of the cpu_active_map. 30639b0fad7SMax Krasnyansky * This is not strictly necessary becuase stop_machine() 30739b0fad7SMax Krasnyansky * that we run down the line already provides the required 30839b0fad7SMax Krasnyansky * synchronization. But it's really a side effect and we do not 30939b0fad7SMax Krasnyansky * want to depend on the innards of the stop_machine here. 31039b0fad7SMax Krasnyansky */ 31139b0fad7SMax Krasnyansky synchronize_sched(); 31239b0fad7SMax Krasnyansky 3138bb78442SRafael J. Wysocki err = _cpu_down(cpu, 0); 314e3920fb4SRafael J. Wysocki 315e761b772SMax Krasnyansky if (cpu_online(cpu)) 316e761b772SMax Krasnyansky cpu_set(cpu, cpu_active_map); 317e761b772SMax Krasnyansky 318e761b772SMax Krasnyansky out: 319d221938cSGautham R Shenoy cpu_maps_update_done(); 3201da177e4SLinus Torvalds return err; 3211da177e4SLinus Torvalds } 322b62b8ef9SZhang Rui EXPORT_SYMBOL(cpu_down); 3231da177e4SLinus Torvalds #endif /*CONFIG_HOTPLUG_CPU*/ 3241da177e4SLinus Torvalds 325e3920fb4SRafael J. Wysocki /* Requires cpu_add_remove_lock to be held */ 3268bb78442SRafael J. Wysocki static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) 3271da177e4SLinus Torvalds { 328baaca49fSGautham R Shenoy int ret, nr_calls = 0; 3291da177e4SLinus Torvalds void *hcpu = (void *)(long)cpu; 3308bb78442SRafael J. Wysocki unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; 3311da177e4SLinus Torvalds 332e3920fb4SRafael J. Wysocki if (cpu_online(cpu) || !cpu_present(cpu)) 333e3920fb4SRafael J. Wysocki return -EINVAL; 33490d45d17SAshok Raj 335d221938cSGautham R Shenoy cpu_hotplug_begin(); 3368bb78442SRafael J. Wysocki ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu, 337baaca49fSGautham R Shenoy -1, &nr_calls); 3381da177e4SLinus Torvalds if (ret == NOTIFY_BAD) { 339a0d8cdb6SAkinobu Mita nr_calls--; 3401da177e4SLinus Torvalds printk("%s: attempt to bring up CPU %u failed\n", 341af1f16d0SHarvey Harrison __func__, cpu); 3421da177e4SLinus Torvalds ret = -EINVAL; 3431da177e4SLinus Torvalds goto out_notify; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds /* Arch-specific enabling code. */ 3471da177e4SLinus Torvalds ret = __cpu_up(cpu); 3481da177e4SLinus Torvalds if (ret != 0) 3491da177e4SLinus Torvalds goto out_notify; 3506978c705SEric Sesterhenn BUG_ON(!cpu_online(cpu)); 3511da177e4SLinus Torvalds 352*279ef6bbSDmitry Adamushko cpu_set(cpu, cpu_active_map); 353*279ef6bbSDmitry Adamushko 3541da177e4SLinus Torvalds /* Now call notifier in preparation. */ 3558bb78442SRafael J. Wysocki raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu); 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds out_notify: 3581da177e4SLinus Torvalds if (ret != 0) 359baaca49fSGautham R Shenoy __raw_notifier_call_chain(&cpu_chain, 3608bb78442SRafael J. Wysocki CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL); 361d221938cSGautham R Shenoy cpu_hotplug_done(); 362e3920fb4SRafael J. Wysocki 3631da177e4SLinus Torvalds return ret; 3641da177e4SLinus Torvalds } 365e3920fb4SRafael J. Wysocki 366b282b6f8SGautham R Shenoy int __cpuinit cpu_up(unsigned int cpu) 367e3920fb4SRafael J. Wysocki { 368e3920fb4SRafael J. Wysocki int err = 0; 36973e753a5SKAMEZAWA Hiroyuki if (!cpu_isset(cpu, cpu_possible_map)) { 37073e753a5SKAMEZAWA Hiroyuki printk(KERN_ERR "can't online cpu %d because it is not " 37173e753a5SKAMEZAWA Hiroyuki "configured as may-hotadd at boot time\n", cpu); 37273e753a5SKAMEZAWA Hiroyuki #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) || defined(CONFIG_S390) 37373e753a5SKAMEZAWA Hiroyuki printk(KERN_ERR "please check additional_cpus= boot " 37473e753a5SKAMEZAWA Hiroyuki "parameter\n"); 37573e753a5SKAMEZAWA Hiroyuki #endif 37673e753a5SKAMEZAWA Hiroyuki return -EINVAL; 37773e753a5SKAMEZAWA Hiroyuki } 378e3920fb4SRafael J. Wysocki 379d221938cSGautham R Shenoy cpu_maps_update_begin(); 380e761b772SMax Krasnyansky 381e761b772SMax Krasnyansky if (cpu_hotplug_disabled) { 382e3920fb4SRafael J. Wysocki err = -EBUSY; 383e761b772SMax Krasnyansky goto out; 384e761b772SMax Krasnyansky } 385e761b772SMax Krasnyansky 3868bb78442SRafael J. Wysocki err = _cpu_up(cpu, 0); 387e3920fb4SRafael J. Wysocki 388e761b772SMax Krasnyansky out: 389d221938cSGautham R Shenoy cpu_maps_update_done(); 390e3920fb4SRafael J. Wysocki return err; 391e3920fb4SRafael J. Wysocki } 392e3920fb4SRafael J. Wysocki 393f3de4be9SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_SMP 394e3920fb4SRafael J. Wysocki static cpumask_t frozen_cpus; 395e3920fb4SRafael J. Wysocki 396e3920fb4SRafael J. Wysocki int disable_nonboot_cpus(void) 397e3920fb4SRafael J. Wysocki { 398e1d9fd2eSIngo Molnar int cpu, first_cpu, error = 0; 399e3920fb4SRafael J. Wysocki 400d221938cSGautham R Shenoy cpu_maps_update_begin(); 4011d64b9cbSRafael J. Wysocki first_cpu = first_cpu(cpu_online_map); 402e3920fb4SRafael J. Wysocki /* We take down all of the non-boot CPUs in one shot to avoid races 403e3920fb4SRafael J. Wysocki * with the userspace trying to use the CPU hotplug at the same time 404e3920fb4SRafael J. Wysocki */ 405e3920fb4SRafael J. Wysocki cpus_clear(frozen_cpus); 406e3920fb4SRafael J. Wysocki printk("Disabling non-boot CPUs ...\n"); 407e3920fb4SRafael J. Wysocki for_each_online_cpu(cpu) { 408e3920fb4SRafael J. Wysocki if (cpu == first_cpu) 409e3920fb4SRafael J. Wysocki continue; 4108bb78442SRafael J. Wysocki error = _cpu_down(cpu, 1); 411e3920fb4SRafael J. Wysocki if (!error) { 412e3920fb4SRafael J. Wysocki cpu_set(cpu, frozen_cpus); 413e3920fb4SRafael J. Wysocki printk("CPU%d is down\n", cpu); 414e3920fb4SRafael J. Wysocki } else { 415e3920fb4SRafael J. Wysocki printk(KERN_ERR "Error taking CPU%d down: %d\n", 416e3920fb4SRafael J. Wysocki cpu, error); 417e3920fb4SRafael J. Wysocki break; 418e3920fb4SRafael J. Wysocki } 419e3920fb4SRafael J. Wysocki } 420e3920fb4SRafael J. Wysocki if (!error) { 421e3920fb4SRafael J. Wysocki BUG_ON(num_online_cpus() > 1); 422e3920fb4SRafael J. Wysocki /* Make sure the CPUs won't be enabled by someone else */ 423e3920fb4SRafael J. Wysocki cpu_hotplug_disabled = 1; 424e3920fb4SRafael J. Wysocki } else { 425e1d9fd2eSIngo Molnar printk(KERN_ERR "Non-boot CPUs are not disabled\n"); 426e3920fb4SRafael J. Wysocki } 427d221938cSGautham R Shenoy cpu_maps_update_done(); 428e3920fb4SRafael J. Wysocki return error; 429e3920fb4SRafael J. Wysocki } 430e3920fb4SRafael J. Wysocki 431fa7303e2SSam Ravnborg void __ref enable_nonboot_cpus(void) 432e3920fb4SRafael J. Wysocki { 433e3920fb4SRafael J. Wysocki int cpu, error; 434e3920fb4SRafael J. Wysocki 435e3920fb4SRafael J. Wysocki /* Allow everyone to use the CPU hotplug again */ 436d221938cSGautham R Shenoy cpu_maps_update_begin(); 437e3920fb4SRafael J. Wysocki cpu_hotplug_disabled = 0; 438ed746e3bSRafael J. Wysocki if (cpus_empty(frozen_cpus)) 4391d64b9cbSRafael J. Wysocki goto out; 440e3920fb4SRafael J. Wysocki 441e3920fb4SRafael J. Wysocki printk("Enabling non-boot CPUs ...\n"); 442363ab6f1SMike Travis for_each_cpu_mask_nr(cpu, frozen_cpus) { 4438bb78442SRafael J. Wysocki error = _cpu_up(cpu, 1); 444e3920fb4SRafael J. Wysocki if (!error) { 445e3920fb4SRafael J. Wysocki printk("CPU%d is up\n", cpu); 446e3920fb4SRafael J. Wysocki continue; 447e3920fb4SRafael J. Wysocki } 4481d64b9cbSRafael J. Wysocki printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error); 449e3920fb4SRafael J. Wysocki } 450e3920fb4SRafael J. Wysocki cpus_clear(frozen_cpus); 4511d64b9cbSRafael J. Wysocki out: 452d221938cSGautham R Shenoy cpu_maps_update_done(); 453e3920fb4SRafael J. Wysocki } 454f3de4be9SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_SMP */ 45568f4f1ecSMax Krasnyansky 45668f4f1ecSMax Krasnyansky #endif /* CONFIG_SMP */ 457b8d317d1SMike Travis 458e56b3bc7SLinus Torvalds /* 459e56b3bc7SLinus Torvalds * cpu_bit_bitmap[] is a special, "compressed" data structure that 460e56b3bc7SLinus Torvalds * represents all NR_CPUS bits binary values of 1<<nr. 461e56b3bc7SLinus Torvalds * 462e56b3bc7SLinus Torvalds * It is used by cpumask_of_cpu() to get a constant address to a CPU 463e56b3bc7SLinus Torvalds * mask value that has a single bit set only. 464e56b3bc7SLinus Torvalds */ 465b8d317d1SMike Travis 466e56b3bc7SLinus Torvalds /* cpu_bit_bitmap[0] is empty - so we can back into it */ 467e56b3bc7SLinus Torvalds #define MASK_DECLARE_1(x) [x+1][0] = 1UL << (x) 468e56b3bc7SLinus Torvalds #define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) 469e56b3bc7SLinus Torvalds #define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) 470e56b3bc7SLinus Torvalds #define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) 471b8d317d1SMike Travis 472e56b3bc7SLinus Torvalds const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { 473b8d317d1SMike Travis 474e56b3bc7SLinus Torvalds MASK_DECLARE_8(0), MASK_DECLARE_8(8), 475e56b3bc7SLinus Torvalds MASK_DECLARE_8(16), MASK_DECLARE_8(24), 476e56b3bc7SLinus Torvalds #if BITS_PER_LONG > 32 477e56b3bc7SLinus Torvalds MASK_DECLARE_8(32), MASK_DECLARE_8(40), 478e56b3bc7SLinus Torvalds MASK_DECLARE_8(48), MASK_DECLARE_8(56), 479b8d317d1SMike Travis #endif 480b8d317d1SMike Travis }; 481e56b3bc7SLinus Torvalds EXPORT_SYMBOL_GPL(cpu_bit_bitmap); 482