Blame view

include/linux/stop_machine.h 4.48 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  #ifndef _LINUX_STOP_MACHINE
  #define _LINUX_STOP_MACHINE
1142d8102   Tejun Heo   cpu_stop: impleme...
3

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
  #include <linux/cpu.h>
eeec4fad9   Rusty Russell   stop_machine(): s...
5
  #include <linux/cpumask.h>
bb2eac66e   Paul Gortmaker   stop_machine.h: f...
6
  #include <linux/smp.h>
1142d8102   Tejun Heo   cpu_stop: impleme...
7
  #include <linux/list.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8

1142d8102   Tejun Heo   cpu_stop: impleme...
9
10
11
12
13
14
15
16
17
18
  /*
   * stop_cpu[s]() is simplistic per-cpu maximum priority cpu
   * monopolization mechanism.  The caller can specify a non-sleeping
   * function to be executed on a single or multiple cpus preempting all
   * other processes and monopolizing those cpus until it finishes.
   *
   * Resources for this mechanism are preallocated when a cpu is brought
   * up and requests are guaranteed to be served as long as the target
   * cpus are online.
   */
1142d8102   Tejun Heo   cpu_stop: impleme...
19
  typedef int (*cpu_stop_fn_t)(void *arg);
bbf1bb3ee   Tejun Heo   cpu_stop: add dum...
20
  #ifdef CONFIG_SMP
1142d8102   Tejun Heo   cpu_stop: impleme...
21
22
23
24
25
26
27
28
  struct cpu_stop_work {
  	struct list_head	list;		/* cpu_stopper->works */
  	cpu_stop_fn_t		fn;
  	void			*arg;
  	struct cpu_stop_done	*done;
  };
  
  int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
1be0bd77c   Peter Zijlstra   stop_machine: Int...
29
  int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg);
1142d8102   Tejun Heo   cpu_stop: impleme...
30
31
32
33
  void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
  			 struct cpu_stop_work *work_buf);
  int stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
  int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
bbf1bb3ee   Tejun Heo   cpu_stop: add dum...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  #else	/* CONFIG_SMP */
  
  #include <linux/workqueue.h>
  
  struct cpu_stop_work {
  	struct work_struct	work;
  	cpu_stop_fn_t		fn;
  	void			*arg;
  };
  
  static inline int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg)
  {
  	int ret = -ENOENT;
  	preempt_disable();
  	if (cpu == smp_processor_id())
  		ret = fn(arg);
  	preempt_enable();
  	return ret;
  }
  
  static void stop_one_cpu_nowait_workfn(struct work_struct *work)
  {
  	struct cpu_stop_work *stwork =
  		container_of(work, struct cpu_stop_work, work);
  	preempt_disable();
  	stwork->fn(stwork->arg);
  	preempt_enable();
  }
  
  static inline void stop_one_cpu_nowait(unsigned int cpu,
  				       cpu_stop_fn_t fn, void *arg,
  				       struct cpu_stop_work *work_buf)
  {
  	if (cpu == smp_processor_id()) {
  		INIT_WORK(&work_buf->work, stop_one_cpu_nowait_workfn);
  		work_buf->fn = fn;
  		work_buf->arg = arg;
  		schedule_work(&work_buf->work);
  	}
  }
  
  static inline int stop_cpus(const struct cpumask *cpumask,
  			    cpu_stop_fn_t fn, void *arg)
  {
  	if (cpumask_test_cpu(raw_smp_processor_id(), cpumask))
  		return stop_one_cpu(raw_smp_processor_id(), fn, arg);
  	return -ENOENT;
  }
  
  static inline int try_stop_cpus(const struct cpumask *cpumask,
  				cpu_stop_fn_t fn, void *arg)
  {
  	return stop_cpus(cpumask, fn, arg);
  }
  
  #endif	/* CONFIG_SMP */
1142d8102   Tejun Heo   cpu_stop: impleme...
90
91
92
93
  /*
   * stop_machine "Bogolock": stop the entire machine, disable
   * interrupts.  This is a very heavy lock, which is equivalent to
   * grabbing every spinlock (and more).  So the "read" side to such a
1816315b1   Jonathan Neuschäfer   stop_machine.h: "...
94
   * lock is anything which disables preemption.
1142d8102   Tejun Heo   cpu_stop: impleme...
95
   */
bbf1bb3ee   Tejun Heo   cpu_stop: add dum...
96
  #if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
1142d8102   Tejun Heo   cpu_stop: impleme...
97

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  /**
eeec4fad9   Rusty Russell   stop_machine(): s...
99
   * stop_machine: freeze the machine on all CPUs and run this function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
   * @fn: the function to run
   * @data: the data ptr for the @fn()
eeec4fad9   Rusty Russell   stop_machine(): s...
102
   * @cpus: the cpus to run the @fn() on (NULL = any online cpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
   *
ffdb5976c   Rusty Russell   Simplify stop_mac...
104
   * Description: This causes a thread to be scheduled on every cpu,
25985edce   Lucas De Marchi   Fix common misspe...
105
   * each of which disables interrupts.  The result is that no one is
ffdb5976c   Rusty Russell   Simplify stop_mac...
106
107
   * holding a spinlock or inside any other preempt-disabled region when
   * @fn() runs.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
   *
   * This can be thought of as a very heavy write lock, equivalent to
   * grabbing every spinlock in the kernel. */
41c7bb958   Rusty Russell   cpumask: convert ...
111
  int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  
  /**
eeec4fad9   Rusty Russell   stop_machine(): s...
114
   * __stop_machine: freeze the machine on all CPUs and run this function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
   * @fn: the function to run
   * @data: the data ptr for the @fn
eeec4fad9   Rusty Russell   stop_machine(): s...
117
   * @cpus: the cpus to run the @fn() on (NULL = any online cpu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
   *
ffdb5976c   Rusty Russell   Simplify stop_mac...
119
120
   * Description: This is a special version of the above, which assumes cpus
   * won't come or go while it's being called.  Used by hotplug cpu.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
   */
41c7bb958   Rusty Russell   cpumask: convert ...
122
  int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus);
9ea09af3b   Heiko Carstens   stop_machine: int...
123

f740e6cd0   Tejun Heo   stop_machine: imp...
124
125
  int stop_machine_from_inactive_cpu(int (*fn)(void *), void *data,
  				   const struct cpumask *cpus);
bbf1bb3ee   Tejun Heo   cpu_stop: add dum...
126
  #else	 /* CONFIG_STOP_MACHINE && CONFIG_SMP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127

087a4eb55   Masami Hiramatsu   stopmachine: Defi...
128
129
  static inline int __stop_machine(int (*fn)(void *), void *data,
  				 const struct cpumask *cpus)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  {
f740e6cd0   Tejun Heo   stop_machine: imp...
131
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  	int ret;
f740e6cd0   Tejun Heo   stop_machine: imp...
133
  	local_irq_save(flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  	ret = fn(data);
f740e6cd0   Tejun Heo   stop_machine: imp...
135
  	local_irq_restore(flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
  	return ret;
  }
9ea09af3b   Heiko Carstens   stop_machine: int...
138

087a4eb55   Masami Hiramatsu   stopmachine: Defi...
139
140
141
142
143
  static inline int stop_machine(int (*fn)(void *), void *data,
  			       const struct cpumask *cpus)
  {
  	return __stop_machine(fn, data, cpus);
  }
f740e6cd0   Tejun Heo   stop_machine: imp...
144
145
146
147
148
  static inline int stop_machine_from_inactive_cpu(int (*fn)(void *), void *data,
  						 const struct cpumask *cpus)
  {
  	return __stop_machine(fn, data, cpus);
  }
bbf1bb3ee   Tejun Heo   cpu_stop: add dum...
149
150
  #endif	/* CONFIG_STOP_MACHINE && CONFIG_SMP */
  #endif	/* _LINUX_STOP_MACHINE */