Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /* CPU control.
  2  * (C) 2001, 2002, 2003, 2004 Rusty Russell
  3  *
  4  * This code is licenced under the GPL.
  5  */
  6 #include <linux/proc_fs.h>
  7 #include <linux/smp.h>
  8 #include <linux/init.h>
  9 #include <linux/notifier.h>
 10 #include <linux/sched.h>
 11 #include <linux/unistd.h>
 12 #include <linux/cpu.h>
 13 #include <linux/module.h>
 14 #include <linux/kthread.h>
 15 #include <linux/stop_machine.h>
 16 #include <linux/mutex.h>
 17 #include <linux/ftrace.h>
 18 
 19 /* Serializes the updates to cpu_online_map, cpu_present_map */
 20 static DEFINE_MUTEX(cpu_add_remove_lock);
 21 
 22 static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
 23 
 24 /* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
 25  * Should always be manipulated under cpu_add_remove_lock
 26  */
 27 static int cpu_hotplug_disabled;
 28 
 29 static struct {
 30         struct task_struct *active_writer;
 31         struct mutex lock; /* Synchronizes accesses to refcount, */
 32         /*
 33          * Also blocks the new readers during
 34          * an ongoing cpu hotplug operation.
 35          */
 36         int refcount;
 37         wait_queue_head_t writer_queue;
 38 } cpu_hotplug;
 39 
 40 #define writer_exists() (cpu_hotplug.active_writer != NULL)
 41 
 42 void __init cpu_hotplug_init(void)
 43 {
 44         cpu_hotplug.active_writer = NULL;
 45         mutex_init(&cpu_hotplug.lock);
 46         cpu_hotplug.refcount = 0;
 47         init_waitqueue_head(&cpu_hotplug.writer_queue);
 48 }
 49 
 50 #ifdef CONFIG_HOTPLUG_CPU
 51 
 52 void get_online_cpus(void)
 53 {
 54         might_sleep();
 55         if (cpu_hotplug.active_writer == current)
 56                 return;
 57         mutex_lock(&cpu_hotplug.lock);
 58         cpu_hotplug.refcount++;
 59         mutex_unlock(&cpu_hotplug.lock);
 60 
 61 }
 62 EXPORT_SYMBOL_GPL(get_online_cpus);
 63 
 64 void put_online_cpus(void)
 65 {
 66         if (cpu_hotplug.active_writer == current)
 67                 return;
 68         mutex_lock(&cpu_hotplug.lock);
 69         cpu_hotplug.refcount--;
 70 
 71         if (unlikely(writer_exists()) && !cpu_hotplug.refcount)
 72                 wake_up(&cpu_hotplug.writer_queue);
 73 
 74         mutex_unlock(&cpu_hotplug.lock);
 75 
 76 }
 77 EXPORT_SYMBOL_GPL(put_online_cpus);
 78 
 79 #endif  /* CONFIG_HOTPLUG_CPU */
 80 
 81 /*
 82  * The following two API's must be used when attempting
 83  * to serialize the updates to cpu_online_map, cpu_present_map.
 84  */
 85 void cpu_maps_update_begin(void)
 86 {
 87         mutex_lock(&cpu_add_remove_lock);
 88 }
 89 
 90 void cpu_maps_update_done(void)
 91 {
 92         mutex_unlock(&cpu_add_remove_lock);
 93 }
 94 
 95 /*
 96  * This ensures that the hotplug operation can begin only when the
 97  * refcount goes to zero.
 98  *
 99  * Note that during a cpu-hotplug operation, the new readers, if any,
100  * will be blocked by the cpu_hotplug.lock
101  *
102  * Since cpu_maps_update_begin is always called after invoking
103  * cpu_maps_update_begin, we can be sure that only one writer is active.
104  *
105  * Note that theoretically, there is a possibility of a livelock:
106  * - Refcount goes to zero, last reader wakes up the sleeping
107  *   writer.
108  * - Last reader unlocks the cpu_hotplug.lock.
109  * - A new reader arrives at this moment, bumps up the refcount.
110  * - The writer acquires the cpu_hotplug.lock finds the refcount
111  *   non zero and goes to sleep again.
112  *
113  * However, this is very difficult to achieve in practice since
114  * get_online_cpus() not an api which is called all that often.
115  *
116  */
117 static void cpu_hotplug_begin(void)
118 {
119         DECLARE_WAITQUEUE(wait, current);
120 
121         mutex_lock(&cpu_hotplug.lock);
122 
123         cpu_hotplug.active_writer = current;
124         add_wait_queue_exclusive(&cpu_hotplug.writer_queue, &wait);
125         while (cpu_hotplug.refcount) {
126                 set_current_state(TASK_UNINTERRUPTIBLE);
127                 mutex_unlock(&cpu_hotplug.lock);
128                 schedule();
129                 mutex_lock(&cpu_hotplug.lock);
130         }
131         remove_wait_queue_locked(&cpu_hotplug.writer_queue, &wait);
132 }
133 
134 static void cpu_hotplug_done(void)
135 {
136         cpu_hotplug.active_writer = NULL;
137         mutex_unlock(&cpu_hotplug.lock);
138 }
139 /* Need to know about CPUs going up/down? */
140 int __cpuinit register_cpu_notifier(struct notifier_block *nb)
141 {
142         int ret;
143         cpu_maps_update_begin();
144         ret = raw_notifier_chain_register(&cpu_chain, nb);
145         cpu_maps_update_done();
146         return ret;
147 }
148 
149 #ifdef CONFIG_HOTPLUG_CPU
150 
151 EXPORT_SYMBOL(register_cpu_notifier);
152 
153 void unregister_cpu_notifier(struct notifier_block *nb)
154 {
155         cpu_maps_update_begin();
156         raw_notifier_chain_unregister(&cpu_chain, nb);
157         cpu_maps_update_done();
158 }
159 EXPORT_SYMBOL(unregister_cpu_notifier);
160 
161 static inline void check_for_tasks(int cpu)
162 {
163         struct task_struct *p;
164 
165         write_lock_irq(&tasklist_lock);
166         for_each_process(p) {
167                 if (task_cpu(p) == cpu &&
168                     (!cputime_eq(p->utime, cputime_zero) ||
169                      !cputime_eq(p->stime, cputime_zero)))
170                         printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\
171                                 (state = %ld, flags = %x) \n",
172                                  p->comm, task_pid_nr(p), cpu,
173                                  p->state, p->flags);
174         }
175         write_unlock_irq(&tasklist_lock);
176 }
177 
178 struct take_cpu_down_param {
179         unsigned long mod;
180         void *hcpu;
181 };
182 
183 /* Take this CPU down. */
184 static int take_cpu_down(void *_param)
185 {
186         struct take_cpu_down_param *param = _param;
187         int err;
188 
189         raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
190                                 param->hcpu);
191         /* Ensure this CPU doesn't handle any more interrupts. */
192         err = __cpu_disable();
193         if (err < 0)
194                 return err;
195 
196         /* Force idle task to run as soon as we yield: it should
197            immediately notice cpu is offline and die quickly. */
198         sched_idle_next();
199         return 0;
200 }
201 
202 /* Requires cpu_add_remove_lock to be held */
203 static int _cpu_down(unsigned int cpu, int tasks_frozen)
204 {
205         int err, nr_calls = 0;
206         struct task_struct *p;
207         cpumask_t old_allowed, tmp;
208         void *hcpu = (void *)(long)cpu;
209         unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
210         struct take_cpu_down_param tcd_param = {
211                 .mod = mod,
212                 .hcpu = hcpu,
213         };
214 
215         if (num_online_cpus() == 1)
216                 return -EBUSY;
217 
218         if (!cpu_online(cpu))
219                 return -EINVAL;
220 
221         cpu_hotplug_begin();
222         err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
223                                         hcpu, -1, &nr_calls);
224         if (err == NOTIFY_BAD) {
225                 nr_calls--;
226                 __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
227                                           hcpu, nr_calls, NULL);
228                 printk("%s: attempt to take down CPU %u failed\n",
229                                 __FUNCTION__, cpu);
230                 err = -EINVAL;
231                 goto out_release;
232         }
233 
234         /* Ensure that we are not runnable on dying cpu */
235         old_allowed = current->cpus_allowed;
236         tmp = CPU_MASK_ALL;
237         cpu_clear(cpu, tmp);
238         set_cpus_allowed(current, tmp);
239 
240         p = __stop_machine_run(take_cpu_down, &tcd_param, cpu);
241 
242         if (IS_ERR(p) || cpu_online(cpu)) {
243                 /* CPU didn't die: tell everyone.  Can't complain. */
244                 if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
245                                             hcpu) == NOTIFY_BAD)
246                         BUG();
247 
248                 if (IS_ERR(p)) {
249                         err = PTR_ERR(p);
250                         goto out_allowed;
251                 }
252                 goto out_thread;
253         }
254 
255         /* Wait for it to sleep (leaving idle task). */
256         while (!idle_cpu(cpu))
257                 yield();
258 
259         /* This actually kills the CPU. */
260         __cpu_die(cpu);
261 
262         /* CPU is completely dead: tell everyone.  Too late to complain. */
263         if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod,
264                                     hcpu) == NOTIFY_BAD)
265                 BUG();
266 
267         check_for_tasks(cpu);
268 
269 out_thread:
270         err = kthread_stop(p);
271 out_allowed:
272         set_cpus_allowed(current, old_allowed);
273 out_release:
274         cpu_hotplug_done();
275         return err;
276 }
277 
278 int cpu_down(unsigned int cpu)
279 {
280         int err = 0;
281 
282         cpu_maps_update_begin();
283         if (cpu_hotplug_disabled)
284                 err = -EBUSY;
285         else
286                 err = _cpu_down(cpu, 0);
287 
288         cpu_maps_update_done();
289         return err;
290 }
291 #endif /*CONFIG_HOTPLUG_CPU*/
292 
293 /* Requires cpu_add_remove_lock to be held */
294 static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
295 {
296         int ret, nr_calls = 0;
297         void *hcpu = (void *)(long)cpu;
298         unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
299 
300         if (cpu_online(cpu) || !cpu_present(cpu))
301                 return -EINVAL;
302 
303         cpu_hotplug_begin();
304         ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
305                                                         -1, &nr_calls);
306         if (ret == NOTIFY_BAD) {
307                 nr_calls--;
308                 printk("%s: attempt to bring up CPU %u failed\n",
309                                 __FUNCTION__, cpu);
310                 ret = -EINVAL;
311                 goto out_notify;
312         }
313 
314         /*
315          * Disable function tracing while bringing up a new CPU.
316          * We don't want to trace functions that can not handle a
317          * smp_processor_id() call.
318          */
319         ftrace_disable();
320 
321         /* Arch-specific enabling code. */
322         ret = __cpu_up(cpu);
323         ftrace_enable();
324         if (ret != 0)
325                 goto out_notify;
326         BUG_ON(!cpu_online(cpu));
327 
328         /* Now call notifier in preparation. */
329         raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
330 
331 out_notify:
332         if (ret != 0)
333                 __raw_notifier_call_chain(&cpu_chain,
334                                 CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
335         cpu_hotplug_done();
336 
337         return ret;
338 }
339 
340 int __cpuinit cpu_up(unsigned int cpu)
341 {
342         int err = 0;
343         if (!cpu_isset(cpu, cpu_possible_map)) {
344                 printk(KERN_ERR "can't online cpu %d because it is not "
345                         "configured as may-hotadd at boot time\n", cpu);
346 #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) || defined(CONFIG_S390)
347                 printk(KERN_ERR "please check additional_cpus= boot "
348                                 "parameter\n");
349 #endif
350                 return -EINVAL;
351         }
352 
353         cpu_maps_update_begin();
354         if (cpu_hotplug_disabled)
355                 err = -EBUSY;
356         else
357                 err = _cpu_up(cpu, 0);
358 
359         cpu_maps_update_done();
360         return err;
361 }
362 
363 #ifdef CONFIG_PM_SLEEP_SMP
364 static cpumask_t frozen_cpus;
365 
366 int disable_nonboot_cpus(void)
367 {
368         int cpu, first_cpu, error = 0;
369 
370         cpu_maps_update_begin();
371         first_cpu = first_cpu(cpu_online_map);
372         /* We take down all of the non-boot CPUs in one shot to avoid races
373          * with the userspace trying to use the CPU hotplug at the same time
374          */
375         cpus_clear(frozen_cpus);
376         printk("Disabling non-boot CPUs ...\n");
377         for_each_online_cpu(cpu) {
378                 if (cpu == first_cpu)
379                         continue;
380                 error = _cpu_down(cpu, 1);
381                 if (!error) {
382                         cpu_set(cpu, frozen_cpus);
383                         printk("CPU%d is down\n", cpu);
384                 } else {
385                         printk(KERN_ERR "Error taking CPU%d down: %d\n",
386                                 cpu, error);
387                         break;
388                 }
389         }
390         if (!error) {
391                 BUG_ON(num_online_cpus() > 1);
392                 /* Make sure the CPUs won't be enabled by someone else */
393                 cpu_hotplug_disabled = 1;
394         } else {
395                 printk(KERN_ERR "Non-boot CPUs are not disabled\n");
396         }
397         cpu_maps_update_done();
398         return error;
399 }
400 
401 void __ref enable_nonboot_cpus(void)
402 {
403         int cpu, error;
404 
405         /* Allow everyone to use the CPU hotplug again */
406         cpu_maps_update_begin();
407         cpu_hotplug_disabled = 0;
408         if (cpus_empty(frozen_cpus))
409                 goto out;
410 
411         printk("Enabling non-boot CPUs ...\n");
412         for_each_cpu_mask(cpu, frozen_cpus) {
413                 error = _cpu_up(cpu, 1);
414                 if (!error) {
415                         printk("CPU%d is up\n", cpu);
416                         continue;
417                 }
418                 printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
419         }
420         cpus_clear(frozen_cpus);
421 out:
422         cpu_maps_update_done();
423 }
424 #endif /* CONFIG_PM_SLEEP_SMP */
425 
  This page was automatically generated by the LXR engine.