diff options
author | Tejun Heo <tj@kernel.org> | 2011-06-23 14:19:28 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2011-06-27 18:17:08 -0400 |
commit | f740e6cd0cb5e7468e46831aeb4d9c30e03d5ebc (patch) | |
tree | 83d81928de5d3ebc3b325f633dddd77a0e6ad662 /include | |
parent | fd7355ba1e936487f5aae6fc058c6cb300e44a64 (diff) |
stop_machine: implement stop_machine_from_inactive_cpu()
Currently, mtrr wants stop_machine functionality while a CPU is being
brought up. As stop_machine() requires the calling CPU to be active,
mtrr implements its own stop_machine using stop_one_cpu() on each
online CPU. This doesn't only unnecessarily duplicate complex logic
but also introduces a possibility of deadlock when it races against
the generic stop_machine().
This patch implements stop_machine_from_inactive_cpu() to serve such
use cases. Its functionality is basically the same as stop_machine();
however, it should be called from a CPU which isn't active and doesn't
depend on working scheduling on the calling CPU.
This is achieved by using busy loops for synchronization and
open-coding stop_cpus queuing and waiting with direct invocation of
fn() for local CPU inbetween.
Signed-off-by: Tejun Heo <tj@kernel.org>
Link: http://lkml.kernel.org/r/20110623182056.982526827@sbsiddha-MOBL3.sc.intel.com
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/stop_machine.h | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h index 14d3524d1274..e0f2da25d751 100644 --- a/include/linux/stop_machine.h +++ b/include/linux/stop_machine.h | |||
@@ -126,15 +126,19 @@ int stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); | |||
126 | */ | 126 | */ |
127 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); | 127 | int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus); |
128 | 128 | ||
129 | int stop_machine_from_inactive_cpu(int (*fn)(void *), void *data, | ||
130 | const struct cpumask *cpus); | ||
131 | |||
129 | #else /* CONFIG_STOP_MACHINE && CONFIG_SMP */ | 132 | #else /* CONFIG_STOP_MACHINE && CONFIG_SMP */ |
130 | 133 | ||
131 | static inline int __stop_machine(int (*fn)(void *), void *data, | 134 | static inline int __stop_machine(int (*fn)(void *), void *data, |
132 | const struct cpumask *cpus) | 135 | const struct cpumask *cpus) |
133 | { | 136 | { |
137 | unsigned long flags; | ||
134 | int ret; | 138 | int ret; |
135 | local_irq_disable(); | 139 | local_irq_save(flags); |
136 | ret = fn(data); | 140 | ret = fn(data); |
137 | local_irq_enable(); | 141 | local_irq_restore(flags); |
138 | return ret; | 142 | return ret; |
139 | } | 143 | } |
140 | 144 | ||
@@ -144,5 +148,11 @@ static inline int stop_machine(int (*fn)(void *), void *data, | |||
144 | return __stop_machine(fn, data, cpus); | 148 | return __stop_machine(fn, data, cpus); |
145 | } | 149 | } |
146 | 150 | ||
151 | static inline int stop_machine_from_inactive_cpu(int (*fn)(void *), void *data, | ||
152 | const struct cpumask *cpus) | ||
153 | { | ||
154 | return __stop_machine(fn, data, cpus); | ||
155 | } | ||
156 | |||
147 | #endif /* CONFIG_STOP_MACHINE && CONFIG_SMP */ | 157 | #endif /* CONFIG_STOP_MACHINE && CONFIG_SMP */ |
148 | #endif /* _LINUX_STOP_MACHINE */ | 158 | #endif /* _LINUX_STOP_MACHINE */ |