aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r--arch/arm/kernel/smp.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 72024ea8a3a6..dc894ab3622b 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -25,6 +25,7 @@
25#include <linux/clockchips.h> 25#include <linux/clockchips.h>
26#include <linux/completion.h> 26#include <linux/completion.h>
27#include <linux/cpufreq.h> 27#include <linux/cpufreq.h>
28#include <linux/irq_work.h>
28 29
29#include <linux/atomic.h> 30#include <linux/atomic.h>
30#include <asm/smp.h> 31#include <asm/smp.h>
@@ -66,6 +67,8 @@ enum ipi_msg_type {
66 IPI_CALL_FUNC, 67 IPI_CALL_FUNC,
67 IPI_CALL_FUNC_SINGLE, 68 IPI_CALL_FUNC_SINGLE,
68 IPI_CPU_STOP, 69 IPI_CPU_STOP,
70 IPI_IRQ_WORK,
71 IPI_COMPLETION,
69}; 72};
70 73
71static DECLARE_COMPLETION(cpu_running); 74static DECLARE_COMPLETION(cpu_running);
@@ -80,7 +83,7 @@ void __init smp_set_ops(struct smp_operations *ops)
80 83
81static unsigned long get_arch_pgd(pgd_t *pgd) 84static unsigned long get_arch_pgd(pgd_t *pgd)
82{ 85{
83 phys_addr_t pgdir = virt_to_phys(pgd); 86 phys_addr_t pgdir = virt_to_idmap(pgd);
84 BUG_ON(pgdir & ARCH_PGD_MASK); 87 BUG_ON(pgdir & ARCH_PGD_MASK);
85 return pgdir >> ARCH_PGD_SHIFT; 88 return pgdir >> ARCH_PGD_SHIFT;
86} 89}
@@ -448,6 +451,14 @@ void arch_send_call_function_single_ipi(int cpu)
448 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); 451 smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
449} 452}
450 453
454#ifdef CONFIG_IRQ_WORK
455void arch_irq_work_raise(void)
456{
457 if (is_smp())
458 smp_cross_call(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
459}
460#endif
461
451static const char *ipi_types[NR_IPI] = { 462static const char *ipi_types[NR_IPI] = {
452#define S(x,s) [x] = s 463#define S(x,s) [x] = s
453 S(IPI_WAKEUP, "CPU wakeup interrupts"), 464 S(IPI_WAKEUP, "CPU wakeup interrupts"),
@@ -456,6 +467,8 @@ static const char *ipi_types[NR_IPI] = {
456 S(IPI_CALL_FUNC, "Function call interrupts"), 467 S(IPI_CALL_FUNC, "Function call interrupts"),
457 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), 468 S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
458 S(IPI_CPU_STOP, "CPU stop interrupts"), 469 S(IPI_CPU_STOP, "CPU stop interrupts"),
470 S(IPI_IRQ_WORK, "IRQ work interrupts"),
471 S(IPI_COMPLETION, "completion interrupts"),
459}; 472};
460 473
461void show_ipi_list(struct seq_file *p, int prec) 474void show_ipi_list(struct seq_file *p, int prec)
@@ -515,6 +528,19 @@ static void ipi_cpu_stop(unsigned int cpu)
515 cpu_relax(); 528 cpu_relax();
516} 529}
517 530
531static DEFINE_PER_CPU(struct completion *, cpu_completion);
532
533int register_ipi_completion(struct completion *completion, int cpu)
534{
535 per_cpu(cpu_completion, cpu) = completion;
536 return IPI_COMPLETION;
537}
538
539static void ipi_complete(unsigned int cpu)
540{
541 complete(per_cpu(cpu_completion, cpu));
542}
543
518/* 544/*
519 * Main handler for inter-processor interrupts 545 * Main handler for inter-processor interrupts
520 */ 546 */
@@ -565,6 +591,20 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
565 irq_exit(); 591 irq_exit();
566 break; 592 break;
567 593
594#ifdef CONFIG_IRQ_WORK
595 case IPI_IRQ_WORK:
596 irq_enter();
597 irq_work_run();
598 irq_exit();
599 break;
600#endif
601
602 case IPI_COMPLETION:
603 irq_enter();
604 ipi_complete(cpu);
605 irq_exit();
606 break;
607
568 default: 608 default:
569 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", 609 printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
570 cpu, ipinr); 610 cpu, ipinr);