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 2021da177e4SLinus Torvalds /* Ensure this CPU doesn't handle any more interrupts. */ 2031da177e4SLinus Torvalds err = __cpu_disable(); 2041da177e4SLinus Torvalds if (err < 0) 205f3705136SZwane Mwaikambo return err; 206f3705136SZwane Mwaikambo 207*3ba35573SManfred Spraul raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod, 208*3ba35573SManfred Spraul param->hcpu); 209*3ba35573SManfred Spraul 2101da177e4SLinus Torvalds /* Force idle task to run as soon as we yield: it should 2111da177e4SLinus Torvalds immediately notice cpu is offline and die quickly. */ 2121da177e4SLinus Torvalds sched_idle_next(); 213f3705136SZwane Mwaikambo return 0; 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 216e3920fb4SRafael J. Wysocki /* Requires cpu_add_remove_lock to be held */ 217514a20a5SSam Ravnborg static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) 2181da177e4SLinus Torvalds { 219e7407dccSHeiko Carstens int err, nr_calls = 0; 2201da177e4SLinus Torvalds cpumask_t old_allowed, tmp; 221e7407dccSHeiko Carstens void *hcpu = (void *)(long)cpu; 2228bb78442SRafael J. Wysocki unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; 223db912f96SAvi Kivity struct take_cpu_down_param tcd_param = { 224db912f96SAvi Kivity .mod = mod, 225db912f96SAvi Kivity .hcpu = hcpu, 226db912f96SAvi Kivity }; 2271da177e4SLinus Torvalds 228e3920fb4SRafael J. Wysocki if (num_online_cpus() == 1) 229e3920fb4SRafael J. Wysocki return -EBUSY; 2301da177e4SLinus Torvalds 231e3920fb4SRafael J. Wysocki if (!cpu_online(cpu)) 232e3920fb4SRafael J. Wysocki return -EINVAL; 2331da177e4SLinus Torvalds 234d221938cSGautham R Shenoy cpu_hotplug_begin(); 2358bb78442SRafael J. Wysocki err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod, 236e7407dccSHeiko Carstens hcpu, -1, &nr_calls); 2371da177e4SLinus Torvalds if (err == NOTIFY_BAD) { 238a0d8cdb6SAkinobu Mita nr_calls--; 2398bb78442SRafael J. Wysocki __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, 2408bb78442SRafael J. Wysocki hcpu, nr_calls, NULL); 2411da177e4SLinus Torvalds printk("%s: attempt to take down CPU %u failed\n", 242af1f16d0SHarvey Harrison __func__, cpu); 243baaca49fSGautham R Shenoy err = -EINVAL; 244baaca49fSGautham R Shenoy goto out_release; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds /* Ensure that we are not runnable on dying cpu */ 2481da177e4SLinus Torvalds old_allowed = current->cpus_allowed; 249f70316daSMike Travis cpus_setall(tmp); 2501da177e4SLinus Torvalds cpu_clear(cpu, tmp); 251f70316daSMike Travis set_cpus_allowed_ptr(current, &tmp); 252eeec4fadSRusty Russell tmp = cpumask_of_cpu(cpu); 2531da177e4SLinus Torvalds 254eeec4fadSRusty Russell err = __stop_machine(take_cpu_down, &tcd_param, &tmp); 25504321587SRusty Russell if (err) { 2561da177e4SLinus Torvalds /* CPU didn't die: tell everyone. Can't complain. */ 2578bb78442SRafael J. Wysocki if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, 258e7407dccSHeiko Carstens hcpu) == NOTIFY_BAD) 2591da177e4SLinus Torvalds BUG(); 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds goto out_allowed; 2621da177e4SLinus Torvalds } 26304321587SRusty Russell BUG_ON(cpu_online(cpu)); 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds /* Wait for it to sleep (leaving idle task). */ 2661da177e4SLinus Torvalds while (!idle_cpu(cpu)) 2671da177e4SLinus Torvalds yield(); 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds /* This actually kills the CPU. */ 2701da177e4SLinus Torvalds __cpu_die(cpu); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds /* CPU is completely dead: tell everyone. Too late to complain. */ 2738bb78442SRafael J. Wysocki if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod, 2748bb78442SRafael J. Wysocki hcpu) == NOTIFY_BAD) 2751da177e4SLinus Torvalds BUG(); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds check_for_tasks(cpu); 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds out_allowed: 280f70316daSMike Travis set_cpus_allowed_ptr(current, &old_allowed); 281baaca49fSGautham R Shenoy out_release: 282d221938cSGautham R Shenoy cpu_hotplug_done(); 2833da1c84cSOleg Nesterov if (!err) { 2843da1c84cSOleg Nesterov if (raw_notifier_call_chain(&cpu_chain, CPU_POST_DEAD | mod, 2853da1c84cSOleg Nesterov hcpu) == NOTIFY_BAD) 2863da1c84cSOleg Nesterov BUG(); 2873da1c84cSOleg Nesterov } 288e3920fb4SRafael J. Wysocki return err; 289e3920fb4SRafael J. Wysocki } 290e3920fb4SRafael J. Wysocki 291514a20a5SSam Ravnborg int __ref cpu_down(unsigned int cpu) 292e3920fb4SRafael J. Wysocki { 293e3920fb4SRafael J. Wysocki int err = 0; 294e3920fb4SRafael J. Wysocki 295d221938cSGautham R Shenoy cpu_maps_update_begin(); 296e761b772SMax Krasnyansky 297e761b772SMax Krasnyansky if (cpu_hotplug_disabled) { 298e3920fb4SRafael J. Wysocki err = -EBUSY; 299e761b772SMax Krasnyansky goto out; 300e761b772SMax Krasnyansky } 301e761b772SMax Krasnyansky 302e761b772SMax Krasnyansky cpu_clear(cpu, cpu_active_map); 303e761b772SMax Krasnyansky 30439b0fad7SMax Krasnyansky /* 30539b0fad7SMax Krasnyansky * Make sure the all cpus did the reschedule and are not 30639b0fad7SMax Krasnyansky * using stale version of the cpu_active_map. 30739b0fad7SMax Krasnyansky * This is not strictly necessary becuase stop_machine() 30839b0fad7SMax Krasnyansky * that we run down the line already provides the required 30939b0fad7SMax Krasnyansky * synchronization. But it's really a side effect and we do not 31039b0fad7SMax Krasnyansky * want to depend on the innards of the stop_machine here. 31139b0fad7SMax Krasnyansky */ 31239b0fad7SMax Krasnyansky synchronize_sched(); 31339b0fad7SMax Krasnyansky 3148bb78442SRafael J. Wysocki err = _cpu_down(cpu, 0); 315e3920fb4SRafael J. Wysocki 316e761b772SMax Krasnyansky if (cpu_online(cpu)) 317e761b772SMax Krasnyansky cpu_set(cpu, cpu_active_map); 318e761b772SMax Krasnyansky 319e761b772SMax Krasnyansky out: 320d221938cSGautham R Shenoy cpu_maps_update_done(); 3211da177e4SLinus Torvalds return err; 3221da177e4SLinus Torvalds } 323b62b8ef9SZhang Rui EXPORT_SYMBOL(cpu_down); 3241da177e4SLinus Torvalds #endif /*CONFIG_HOTPLUG_CPU*/ 3251da177e4SLinus Torvalds 326e3920fb4SRafael J. Wysocki /* Requires cpu_add_remove_lock to be held */ 3278bb78442SRafael J. Wysocki static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) 3281da177e4SLinus Torvalds { 329baaca49fSGautham R Shenoy int ret, nr_calls = 0; 3301da177e4SLinus Torvalds void *hcpu = (void *)(long)cpu; 3318bb78442SRafael J. Wysocki unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; 3321da177e4SLinus Torvalds 333e3920fb4SRafael J. Wysocki if (cpu_online(cpu) || !cpu_present(cpu)) 334e3920fb4SRafael J. Wysocki return -EINVAL; 33590d45d17SAshok Raj 336d221938cSGautham R Shenoy cpu_hotplug_begin(); 3378bb78442SRafael J. Wysocki ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu, 338baaca49fSGautham R Shenoy -1, &nr_calls); 3391da177e4SLinus Torvalds if (ret == NOTIFY_BAD) { 340a0d8cdb6SAkinobu Mita nr_calls--; 3411da177e4SLinus Torvalds printk("%s: attempt to bring up CPU %u failed\n", 342af1f16d0SHarvey Harrison __func__, cpu); 3431da177e4SLinus Torvalds ret = -EINVAL; 3441da177e4SLinus Torvalds goto out_notify; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* Arch-specific enabling code. */ 3481da177e4SLinus Torvalds ret = __cpu_up(cpu); 3491da177e4SLinus Torvalds if (ret != 0) 3501da177e4SLinus Torvalds goto out_notify; 3516978c705SEric Sesterhenn BUG_ON(!cpu_online(cpu)); 3521da177e4SLinus Torvalds 353279ef6bbSDmitry Adamushko cpu_set(cpu, cpu_active_map); 354279ef6bbSDmitry Adamushko 3551da177e4SLinus Torvalds /* Now call notifier in preparation. */ 3568bb78442SRafael J. Wysocki raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu); 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds out_notify: 3591da177e4SLinus Torvalds if (ret != 0) 360baaca49fSGautham R Shenoy __raw_notifier_call_chain(&cpu_chain, 3618bb78442SRafael J. Wysocki CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL); 362d221938cSGautham R Shenoy cpu_hotplug_done(); 363e3920fb4SRafael J. Wysocki 3641da177e4SLinus Torvalds return ret; 3651da177e4SLinus Torvalds } 366e3920fb4SRafael J. Wysocki 367b282b6f8SGautham R Shenoy int __cpuinit cpu_up(unsigned int cpu) 368e3920fb4SRafael J. Wysocki { 369e3920fb4SRafael J. Wysocki int err = 0; 37073e753a5SKAMEZAWA Hiroyuki if (!cpu_isset(cpu, cpu_possible_map)) { 37173e753a5SKAMEZAWA Hiroyuki printk(KERN_ERR "can't online cpu %d because it is not " 37273e753a5SKAMEZAWA Hiroyuki "configured as may-hotadd at boot time\n", cpu); 3733ee1062bSHeiko Carstens #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) 37473e753a5SKAMEZAWA Hiroyuki printk(KERN_ERR "please check additional_cpus= boot " 37573e753a5SKAMEZAWA Hiroyuki "parameter\n"); 37673e753a5SKAMEZAWA Hiroyuki #endif 37773e753a5SKAMEZAWA Hiroyuki return -EINVAL; 37873e753a5SKAMEZAWA Hiroyuki } 379e3920fb4SRafael J. Wysocki 380d221938cSGautham R Shenoy cpu_maps_update_begin(); 381e761b772SMax Krasnyansky 382e761b772SMax Krasnyansky if (cpu_hotplug_disabled) { 383e3920fb4SRafael J. Wysocki err = -EBUSY; 384e761b772SMax Krasnyansky goto out; 385e761b772SMax Krasnyansky } 386e761b772SMax Krasnyansky 3878bb78442SRafael J. Wysocki err = _cpu_up(cpu, 0); 388e3920fb4SRafael J. Wysocki 389e761b772SMax Krasnyansky out: 390d221938cSGautham R Shenoy cpu_maps_update_done(); 391e3920fb4SRafael J. Wysocki return err; 392e3920fb4SRafael J. Wysocki } 393e3920fb4SRafael J. Wysocki 394f3de4be9SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP_SMP 395e3920fb4SRafael J. Wysocki static cpumask_t frozen_cpus; 396e3920fb4SRafael J. Wysocki 397e3920fb4SRafael J. Wysocki int disable_nonboot_cpus(void) 398e3920fb4SRafael J. Wysocki { 399e1d9fd2eSIngo Molnar int cpu, first_cpu, error = 0; 400e3920fb4SRafael J. Wysocki 401d221938cSGautham R Shenoy cpu_maps_update_begin(); 4021d64b9cbSRafael J. Wysocki first_cpu = first_cpu(cpu_online_map); 403e3920fb4SRafael J. Wysocki /* We take down all of the non-boot CPUs in one shot to avoid races 404e3920fb4SRafael J. Wysocki * with the userspace trying to use the CPU hotplug at the same time 405e3920fb4SRafael J. Wysocki */ 406e3920fb4SRafael J. Wysocki cpus_clear(frozen_cpus); 407e3920fb4SRafael J. Wysocki printk("Disabling non-boot CPUs ...\n"); 408e3920fb4SRafael J. Wysocki for_each_online_cpu(cpu) { 409e3920fb4SRafael J. Wysocki if (cpu == first_cpu) 410e3920fb4SRafael J. Wysocki continue; 4118bb78442SRafael J. Wysocki error = _cpu_down(cpu, 1); 412e3920fb4SRafael J. Wysocki if (!error) { 413e3920fb4SRafael J. Wysocki cpu_set(cpu, frozen_cpus); 414e3920fb4SRafael J. Wysocki printk("CPU%d is down\n", cpu); 415e3920fb4SRafael J. Wysocki } else { 416e3920fb4SRafael J. Wysocki printk(KERN_ERR "Error taking CPU%d down: %d\n", 417e3920fb4SRafael J. Wysocki cpu, error); 418e3920fb4SRafael J. Wysocki break; 419e3920fb4SRafael J. Wysocki } 420e3920fb4SRafael J. Wysocki } 421e3920fb4SRafael J. Wysocki if (!error) { 422e3920fb4SRafael J. Wysocki BUG_ON(num_online_cpus() > 1); 423e3920fb4SRafael J. Wysocki /* Make sure the CPUs won't be enabled by someone else */ 424e3920fb4SRafael J. Wysocki cpu_hotplug_disabled = 1; 425e3920fb4SRafael J. Wysocki } else { 426e1d9fd2eSIngo Molnar printk(KERN_ERR "Non-boot CPUs are not disabled\n"); 427e3920fb4SRafael J. Wysocki } 428d221938cSGautham R Shenoy cpu_maps_update_done(); 429e3920fb4SRafael J. Wysocki return error; 430e3920fb4SRafael J. Wysocki } 431e3920fb4SRafael J. Wysocki 432fa7303e2SSam Ravnborg void __ref enable_nonboot_cpus(void) 433e3920fb4SRafael J. Wysocki { 434e3920fb4SRafael J. Wysocki int cpu, error; 435e3920fb4SRafael J. Wysocki 436e3920fb4SRafael J. Wysocki /* Allow everyone to use the CPU hotplug again */ 437d221938cSGautham R Shenoy cpu_maps_update_begin(); 438e3920fb4SRafael J. Wysocki cpu_hotplug_disabled = 0; 439ed746e3bSRafael J. Wysocki if (cpus_empty(frozen_cpus)) 4401d64b9cbSRafael J. Wysocki goto out; 441e3920fb4SRafael J. Wysocki 442e3920fb4SRafael J. Wysocki printk("Enabling non-boot CPUs ...\n"); 443363ab6f1SMike Travis for_each_cpu_mask_nr(cpu, frozen_cpus) { 4448bb78442SRafael J. Wysocki error = _cpu_up(cpu, 1); 445e3920fb4SRafael J. Wysocki if (!error) { 446e3920fb4SRafael J. Wysocki printk("CPU%d is up\n", cpu); 447e3920fb4SRafael J. Wysocki continue; 448e3920fb4SRafael J. Wysocki } 4491d64b9cbSRafael J. Wysocki printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error); 450e3920fb4SRafael J. Wysocki } 451e3920fb4SRafael J. Wysocki cpus_clear(frozen_cpus); 4521d64b9cbSRafael J. Wysocki out: 453d221938cSGautham R Shenoy cpu_maps_update_done(); 454e3920fb4SRafael J. Wysocki } 455f3de4be9SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP_SMP */ 45668f4f1ecSMax Krasnyansky 45768f4f1ecSMax Krasnyansky #endif /* CONFIG_SMP */ 458b8d317d1SMike Travis 459e56b3bc7SLinus Torvalds /* 460e56b3bc7SLinus Torvalds * cpu_bit_bitmap[] is a special, "compressed" data structure that 461e56b3bc7SLinus Torvalds * represents all NR_CPUS bits binary values of 1<<nr. 462e56b3bc7SLinus Torvalds * 463e56b3bc7SLinus Torvalds * It is used by cpumask_of_cpu() to get a constant address to a CPU 464e56b3bc7SLinus Torvalds * mask value that has a single bit set only. 465e56b3bc7SLinus Torvalds */ 466b8d317d1SMike Travis 467e56b3bc7SLinus Torvalds /* cpu_bit_bitmap[0] is empty - so we can back into it */ 468e56b3bc7SLinus Torvalds #define MASK_DECLARE_1(x) [x+1][0] = 1UL << (x) 469e56b3bc7SLinus Torvalds #define MASK_DECLARE_2(x) MASK_DECLARE_1(x), MASK_DECLARE_1(x+1) 470e56b3bc7SLinus Torvalds #define MASK_DECLARE_4(x) MASK_DECLARE_2(x), MASK_DECLARE_2(x+2) 471e56b3bc7SLinus Torvalds #define MASK_DECLARE_8(x) MASK_DECLARE_4(x), MASK_DECLARE_4(x+4) 472b8d317d1SMike Travis 473e56b3bc7SLinus Torvalds const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { 474b8d317d1SMike Travis 475e56b3bc7SLinus Torvalds MASK_DECLARE_8(0), MASK_DECLARE_8(8), 476e56b3bc7SLinus Torvalds MASK_DECLARE_8(16), MASK_DECLARE_8(24), 477e56b3bc7SLinus Torvalds #if BITS_PER_LONG > 32 478e56b3bc7SLinus Torvalds MASK_DECLARE_8(32), MASK_DECLARE_8(40), 479e56b3bc7SLinus Torvalds MASK_DECLARE_8(48), MASK_DECLARE_8(56), 480b8d317d1SMike Travis #endif 481b8d317d1SMike Travis }; 482e56b3bc7SLinus Torvalds EXPORT_SYMBOL_GPL(cpu_bit_bitmap); 483