diff options
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/sigp.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/smp.h | 5 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 175 |
4 files changed, 24 insertions, 158 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 37bb37334dec..7899f0bce658 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -73,6 +73,7 @@ mainmenu "Linux Kernel Configuration" | |||
73 | 73 | ||
74 | config S390 | 74 | config S390 |
75 | def_bool y | 75 | def_bool y |
76 | select USE_GENERIC_SMP_HELPERS if SMP | ||
76 | select HAVE_OPROFILE | 77 | select HAVE_OPROFILE |
77 | select HAVE_KPROBES | 78 | select HAVE_KPROBES |
78 | select HAVE_KRETPROBES | 79 | select HAVE_KRETPROBES |
diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index e16d56f8dfe1..ec403d4304f8 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h | |||
@@ -61,6 +61,7 @@ typedef enum | |||
61 | { | 61 | { |
62 | ec_schedule=0, | 62 | ec_schedule=0, |
63 | ec_call_function, | 63 | ec_call_function, |
64 | ec_call_function_single, | ||
64 | ec_bit_last | 65 | ec_bit_last |
65 | } ec_bit_sig; | 66 | } ec_bit_sig; |
66 | 67 | ||
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index ae89cf2478fc..024b91e06239 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h | |||
@@ -91,8 +91,9 @@ extern int __cpu_up (unsigned int cpu); | |||
91 | extern struct mutex smp_cpu_state_mutex; | 91 | extern struct mutex smp_cpu_state_mutex; |
92 | extern int smp_cpu_polarization[]; | 92 | extern int smp_cpu_polarization[]; |
93 | 93 | ||
94 | extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), | 94 | extern void arch_send_call_function_single_ipi(int cpu); |
95 | void *info, int wait); | 95 | extern void arch_send_call_function_ipi(cpumask_t mask); |
96 | |||
96 | #endif | 97 | #endif |
97 | 98 | ||
98 | #ifndef CONFIG_SMP | 99 | #ifndef CONFIG_SMP |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index b5595688a477..176a43e5b8b4 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -77,159 +77,6 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); | |||
77 | 77 | ||
78 | static void smp_ext_bitcall(int, ec_bit_sig); | 78 | static void smp_ext_bitcall(int, ec_bit_sig); |
79 | 79 | ||
80 | /* | ||
81 | * Structure and data for __smp_call_function_map(). This is designed to | ||
82 | * minimise static memory requirements. It also looks cleaner. | ||
83 | */ | ||
84 | static DEFINE_SPINLOCK(call_lock); | ||
85 | |||
86 | struct call_data_struct { | ||
87 | void (*func) (void *info); | ||
88 | void *info; | ||
89 | cpumask_t started; | ||
90 | cpumask_t finished; | ||
91 | int wait; | ||
92 | }; | ||
93 | |||
94 | static struct call_data_struct *call_data; | ||
95 | |||
96 | /* | ||
97 | * 'Call function' interrupt callback | ||
98 | */ | ||
99 | static void do_call_function(void) | ||
100 | { | ||
101 | void (*func) (void *info) = call_data->func; | ||
102 | void *info = call_data->info; | ||
103 | int wait = call_data->wait; | ||
104 | |||
105 | cpu_set(smp_processor_id(), call_data->started); | ||
106 | (*func)(info); | ||
107 | if (wait) | ||
108 | cpu_set(smp_processor_id(), call_data->finished);; | ||
109 | } | ||
110 | |||
111 | static void __smp_call_function_map(void (*func) (void *info), void *info, | ||
112 | int wait, cpumask_t map) | ||
113 | { | ||
114 | struct call_data_struct data; | ||
115 | int cpu, local = 0; | ||
116 | |||
117 | /* | ||
118 | * Can deadlock when interrupts are disabled or if in wrong context. | ||
119 | */ | ||
120 | WARN_ON(irqs_disabled() || in_irq()); | ||
121 | |||
122 | /* | ||
123 | * Check for local function call. We have to have the same call order | ||
124 | * as in on_each_cpu() because of machine_restart_smp(). | ||
125 | */ | ||
126 | if (cpu_isset(smp_processor_id(), map)) { | ||
127 | local = 1; | ||
128 | cpu_clear(smp_processor_id(), map); | ||
129 | } | ||
130 | |||
131 | cpus_and(map, map, cpu_online_map); | ||
132 | if (cpus_empty(map)) | ||
133 | goto out; | ||
134 | |||
135 | data.func = func; | ||
136 | data.info = info; | ||
137 | data.started = CPU_MASK_NONE; | ||
138 | data.wait = wait; | ||
139 | if (wait) | ||
140 | data.finished = CPU_MASK_NONE; | ||
141 | |||
142 | call_data = &data; | ||
143 | |||
144 | for_each_cpu_mask(cpu, map) | ||
145 | smp_ext_bitcall(cpu, ec_call_function); | ||
146 | |||
147 | /* Wait for response */ | ||
148 | while (!cpus_equal(map, data.started)) | ||
149 | cpu_relax(); | ||
150 | if (wait) | ||
151 | while (!cpus_equal(map, data.finished)) | ||
152 | cpu_relax(); | ||
153 | out: | ||
154 | if (local) { | ||
155 | local_irq_disable(); | ||
156 | func(info); | ||
157 | local_irq_enable(); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * smp_call_function: | ||
163 | * @func: the function to run; this must be fast and non-blocking | ||
164 | * @info: an arbitrary pointer to pass to the function | ||
165 | * @wait: if true, wait (atomically) until function has completed on other CPUs | ||
166 | * | ||
167 | * Run a function on all other CPUs. | ||
168 | * | ||
169 | * You must not call this function with disabled interrupts, from a | ||
170 | * hardware interrupt handler or from a bottom half. | ||
171 | */ | ||
172 | int smp_call_function(void (*func) (void *info), void *info, int wait) | ||
173 | { | ||
174 | cpumask_t map; | ||
175 | |||
176 | spin_lock(&call_lock); | ||
177 | map = cpu_online_map; | ||
178 | cpu_clear(smp_processor_id(), map); | ||
179 | __smp_call_function_map(func, info, wait, map); | ||
180 | spin_unlock(&call_lock); | ||
181 | return 0; | ||
182 | } | ||
183 | EXPORT_SYMBOL(smp_call_function); | ||
184 | |||
185 | /* | ||
186 | * smp_call_function_single: | ||
187 | * @cpu: the CPU where func should run | ||
188 | * @func: the function to run; this must be fast and non-blocking | ||
189 | * @info: an arbitrary pointer to pass to the function | ||
190 | * @wait: if true, wait (atomically) until function has completed on other CPUs | ||
191 | * | ||
192 | * Run a function on one processor. | ||
193 | * | ||
194 | * You must not call this function with disabled interrupts, from a | ||
195 | * hardware interrupt handler or from a bottom half. | ||
196 | */ | ||
197 | int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | ||
198 | int wait) | ||
199 | { | ||
200 | spin_lock(&call_lock); | ||
201 | __smp_call_function_map(func, info, wait, cpumask_of_cpu(cpu)); | ||
202 | spin_unlock(&call_lock); | ||
203 | return 0; | ||
204 | } | ||
205 | EXPORT_SYMBOL(smp_call_function_single); | ||
206 | |||
207 | /** | ||
208 | * smp_call_function_mask(): Run a function on a set of other CPUs. | ||
209 | * @mask: The set of cpus to run on. Must not include the current cpu. | ||
210 | * @func: The function to run. This must be fast and non-blocking. | ||
211 | * @info: An arbitrary pointer to pass to the function. | ||
212 | * @wait: If true, wait (atomically) until function has completed on other CPUs. | ||
213 | * | ||
214 | * Returns 0 on success, else a negative status code. | ||
215 | * | ||
216 | * If @wait is true, then returns once @func has returned; otherwise | ||
217 | * it returns just before the target cpu calls @func. | ||
218 | * | ||
219 | * You must not call this function with disabled interrupts or from a | ||
220 | * hardware interrupt handler or from a bottom half handler. | ||
221 | */ | ||
222 | int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, | ||
223 | int wait) | ||
224 | { | ||
225 | spin_lock(&call_lock); | ||
226 | cpu_clear(smp_processor_id(), mask); | ||
227 | __smp_call_function_map(func, info, wait, mask); | ||
228 | spin_unlock(&call_lock); | ||
229 | return 0; | ||
230 | } | ||
231 | EXPORT_SYMBOL(smp_call_function_mask); | ||
232 | |||
233 | void smp_send_stop(void) | 80 | void smp_send_stop(void) |
234 | { | 81 | { |
235 | int cpu, rc; | 82 | int cpu, rc; |
@@ -271,7 +118,10 @@ static void do_ext_call_interrupt(__u16 code) | |||
271 | bits = xchg(&S390_lowcore.ext_call_fast, 0); | 118 | bits = xchg(&S390_lowcore.ext_call_fast, 0); |
272 | 119 | ||
273 | if (test_bit(ec_call_function, &bits)) | 120 | if (test_bit(ec_call_function, &bits)) |
274 | do_call_function(); | 121 | generic_smp_call_function_interrupt(); |
122 | |||
123 | if (test_bit(ec_call_function_single, &bits)) | ||
124 | generic_smp_call_function_single_interrupt(); | ||
275 | } | 125 | } |
276 | 126 | ||
277 | /* | 127 | /* |
@@ -288,6 +138,19 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig) | |||
288 | udelay(10); | 138 | udelay(10); |
289 | } | 139 | } |
290 | 140 | ||
141 | void arch_send_call_function_ipi(cpumask_t mask) | ||
142 | { | ||
143 | int cpu; | ||
144 | |||
145 | for_each_cpu_mask(cpu, mask) | ||
146 | smp_ext_bitcall(cpu, ec_call_function); | ||
147 | } | ||
148 | |||
149 | void arch_send_call_function_single_ipi(int cpu) | ||
150 | { | ||
151 | smp_ext_bitcall(cpu, ec_call_function_single); | ||
152 | } | ||
153 | |||
291 | #ifndef CONFIG_64BIT | 154 | #ifndef CONFIG_64BIT |
292 | /* | 155 | /* |
293 | * this function sends a 'purge tlb' signal to another CPU. | 156 | * this function sends a 'purge tlb' signal to another CPU. |
@@ -588,9 +451,9 @@ int __cpuinit start_secondary(void *cpuvoid) | |||
588 | /* call cpu notifiers */ | 451 | /* call cpu notifiers */ |
589 | notify_cpu_starting(smp_processor_id()); | 452 | notify_cpu_starting(smp_processor_id()); |
590 | /* Mark this cpu as online */ | 453 | /* Mark this cpu as online */ |
591 | spin_lock(&call_lock); | 454 | ipi_call_lock(); |
592 | cpu_set(smp_processor_id(), cpu_online_map); | 455 | cpu_set(smp_processor_id(), cpu_online_map); |
593 | spin_unlock(&call_lock); | 456 | ipi_call_unlock(); |
594 | /* Switch on interrupts */ | 457 | /* Switch on interrupts */ |
595 | local_irq_enable(); | 458 | local_irq_enable(); |
596 | /* Print info about this processor */ | 459 | /* Print info about this processor */ |