aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-11-28 03:27:54 -0500
committerVineet Gupta <vgupta@synopsys.com>2013-12-23 01:35:04 -0500
commitd8e8c7dda11f5d5cf90495f2e89d917a83509bc0 (patch)
tree8b8414e2bd4ed6b92bf35a36a3d891fa14399661 /arch/arc
parentf2a4aa5646687f9a51616581221b1d348590d47e (diff)
ARC: [SMP] optimize IPI send and receive
* Don't send an IPI if receiver already has a pending IPI. Atomically piggyback the new msg with pending msg. * IPI receiver looping on xchg() not required References: https://lkml.org/lkml/2013/11/25/232 Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Diffstat (limited to 'arch/arc')
-rw-r--r--arch/arc/kernel/smp.c68
1 files changed, 40 insertions, 28 deletions
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index c00c612e8dd3..40859e5619f9 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -215,16 +215,31 @@ static DEFINE_PER_CPU(unsigned long, ipi_data);
215static void ipi_send_msg_one(int cpu, enum ipi_msg_type msg) 215static void ipi_send_msg_one(int cpu, enum ipi_msg_type msg)
216{ 216{
217 unsigned long __percpu *ipi_data_ptr = per_cpu_ptr(&ipi_data, cpu); 217 unsigned long __percpu *ipi_data_ptr = per_cpu_ptr(&ipi_data, cpu);
218 unsigned long old, new;
218 unsigned long flags; 219 unsigned long flags;
219 220
220 pr_debug("%d Sending msg [%d] to %d\n", smp_processor_id(), msg, cpu); 221 pr_debug("%d Sending msg [%d] to %d\n", smp_processor_id(), msg, cpu);
221 222
222 local_irq_save(flags); 223 local_irq_save(flags);
223 224
224 set_bit(msg, ipi_data_ptr); 225 /*
226 * Atomically write new msg bit (in case others are writing too),
227 * and read back old value
228 */
229 do {
230 new = old = *ipi_data_ptr;
231 new |= 1U << msg;
232 } while (cmpxchg(ipi_data_ptr, old, new) != old);
225 233
226 /* Call the platform specific cross-CPU call function */ 234 /*
227 if (plat_smp_ops.ipi_send) 235 * Call the platform specific IPI kick function, but avoid if possible:
236 * Only do so if there's no pending msg from other concurrent sender(s).
237 * Otherwise, recevier will see this msg as well when it takes the
238 * IPI corresponding to that msg. This is true, even if it is already in
239 * IPI handler, because !@old means it has not yet dequeued the msg(s)
240 * so @new msg can be a free-loader
241 */
242 if (plat_smp_ops.ipi_send && !old)
228 plat_smp_ops.ipi_send(cpu); 243 plat_smp_ops.ipi_send(cpu);
229 244
230 local_irq_restore(flags); 245 local_irq_restore(flags);
@@ -269,31 +284,23 @@ static void ipi_cpu_stop(void)
269 machine_halt(); 284 machine_halt();
270} 285}
271 286
272static inline void __do_IPI(unsigned long pending) 287static inline void __do_IPI(unsigned long msg)
273{ 288{
274 while (pending) { 289 switch (msg) {
275 290 case IPI_RESCHEDULE:
276 unsigned long msg = __ffs(pending); 291 scheduler_ipi();
277 292 break;
278 switch (msg) {
279 case IPI_RESCHEDULE:
280 scheduler_ipi();
281 break;
282 293
283 case IPI_CALL_FUNC: 294 case IPI_CALL_FUNC:
284 generic_smp_call_function_interrupt(); 295 generic_smp_call_function_interrupt();
285 break; 296 break;
286
287 case IPI_CPU_STOP:
288 ipi_cpu_stop();
289 break;
290
291 default:
292 pr_warn("IPI missing msg\n");
293 297
294 } 298 case IPI_CPU_STOP:
299 ipi_cpu_stop();
300 break;
295 301
296 pending &= ~(1U << msg); 302 default:
303 pr_warn("IPI with unexpected msg %ld\n", msg);
297 } 304 }
298} 305}
299 306
@@ -312,11 +319,16 @@ irqreturn_t do_IPI(int irq, void *dev_id)
312 plat_smp_ops.ipi_clear(irq); 319 plat_smp_ops.ipi_clear(irq);
313 320
314 /* 321 /*
315 * XXX: is this loop really needed 322 * "dequeue" the msg corresponding to this IPI (and possibly other
316 * And do we need to move ipi_clean inside 323 * piggybacked msg from elided IPIs: see ipi_send_msg_one() above)
317 */ 324 */
318 while ((pending = xchg(this_cpu_ptr(&ipi_data), 0)) != 0) 325 pending = xchg(this_cpu_ptr(&ipi_data), 0);
319 __do_IPI(pending); 326
327 do {
328 unsigned long msg = __ffs(pending);
329 __do_IPI(msg);
330 pending &= ~(1U << msg);
331 } while (pending);
320 332
321 return IRQ_HANDLED; 333 return IRQ_HANDLED;
322} 334}