aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-11-15 04:54:18 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-12-03 03:26:30 -0500
commit24480d980e9063b3ebd0dfdf2f396c305956c356 (patch)
tree0be240f0f376c5bfe38700929adab78956edef06
parentad3b6993b9c5482e8a2ec5aed181538c921fdcbd (diff)
ARM: SMP: avoid using bitmasks and locks for IPIs, use hardware instead
Avoid using bitmasks and locks in the percpu area for IPIs, and instead use individual software generated interrupts to identify the reason for the IPI. This avoids the problems of having spinlocks in the percpu area. Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/kernel/smp.c87
1 files changed, 26 insertions, 61 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 7a236db03fb..78d55c681a4 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -48,20 +48,15 @@ struct secondary_data secondary_data;
48 48
49/* 49/*
50 * structures for inter-processor calls 50 * structures for inter-processor calls
51 * - A collection of single bit ipi messages.
52 */ 51 */
53struct ipi_data { 52struct ipi_data {
54 spinlock_t lock;
55 unsigned long ipi_count; 53 unsigned long ipi_count;
56 unsigned long bits;
57}; 54};
58 55
59static DEFINE_PER_CPU(struct ipi_data, ipi_data) = { 56static DEFINE_PER_CPU(struct ipi_data, ipi_data);
60 .lock = SPIN_LOCK_UNLOCKED,
61};
62 57
63enum ipi_msg_type { 58enum ipi_msg_type {
64 IPI_TIMER, 59 IPI_TIMER = 2,
65 IPI_RESCHEDULE, 60 IPI_RESCHEDULE,
66 IPI_CALL_FUNC, 61 IPI_CALL_FUNC,
67 IPI_CALL_FUNC_SINGLE, 62 IPI_CALL_FUNC_SINGLE,
@@ -389,22 +384,13 @@ void __init smp_prepare_boot_cpu(void)
389static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg) 384static void send_ipi_message(const struct cpumask *mask, enum ipi_msg_type msg)
390{ 385{
391 unsigned long flags; 386 unsigned long flags;
392 unsigned int cpu;
393 387
394 local_irq_save(flags); 388 local_irq_save(flags);
395 389
396 for_each_cpu(cpu, mask) {
397 struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
398
399 spin_lock(&ipi->lock);
400 ipi->bits |= 1 << msg;
401 spin_unlock(&ipi->lock);
402 }
403
404 /* 390 /*
405 * Call the platform specific cross-CPU call function. 391 * Call the platform specific cross-CPU call function.
406 */ 392 */
407 smp_cross_call(mask, 1); 393 smp_cross_call(mask, msg);
408 394
409 local_irq_restore(flags); 395 local_irq_restore(flags);
410} 396}
@@ -546,56 +532,35 @@ asmlinkage void __exception do_IPI(int ipinr, struct pt_regs *regs)
546 532
547 ipi->ipi_count++; 533 ipi->ipi_count++;
548 534
549 for (;;) { 535 switch (ipinr) {
550 unsigned long msgs; 536 case IPI_TIMER:
551 537 ipi_timer();
552 spin_lock(&ipi->lock); 538 break;
553 msgs = ipi->bits;
554 ipi->bits = 0;
555 spin_unlock(&ipi->lock);
556
557 if (!msgs)
558 break;
559
560 do {
561 unsigned nextmsg;
562
563 nextmsg = msgs & -msgs;
564 msgs &= ~nextmsg;
565 nextmsg = ffz(~nextmsg);
566
567 switch (nextmsg) {
568 case IPI_TIMER:
569 ipi_timer();
570 break;
571 539
572 case IPI_RESCHEDULE: 540 case IPI_RESCHEDULE:
573 /* 541 /*
574 * nothing more to do - eveything is 542 * nothing more to do - eveything is
575 * done on the interrupt return path 543 * done on the interrupt return path
576 */ 544 */
577 break; 545 break;
578 546
579 case IPI_CALL_FUNC: 547 case IPI_CALL_FUNC:
580 generic_smp_call_function_interrupt(); 548 generic_smp_call_function_interrupt();
581 break; 549 break;
582 550
583 case IPI_CALL_FUNC_SINGLE: 551 case IPI_CALL_FUNC_SINGLE:
584 generic_smp_call_function_single_interrupt(); 552 generic_smp_call_function_single_interrupt();
585 break; 553 break;
586 554
587 case IPI_CPU_STOP: 555 case IPI_CPU_STOP:
588 ipi_cpu_stop(cpu); 556 ipi_cpu_stop(cpu);
589 break; 557 break;
590 558
591 default: 559 default:
592 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", 560 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
593 cpu, nextmsg); 561 cpu, ipinr);
594 break; 562 break;
595 }
596 } while (msgs);
597 } 563 }
598
599 set_irq_regs(old_regs); 564 set_irq_regs(old_regs);
600} 565}
601 566