diff options
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r-- | arch/arm/kernel/smp.c | 42 |
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 | ||
71 | static DECLARE_COMPLETION(cpu_running); | 74 | static DECLARE_COMPLETION(cpu_running); |
@@ -80,7 +83,7 @@ void __init smp_set_ops(struct smp_operations *ops) | |||
80 | 83 | ||
81 | static unsigned long get_arch_pgd(pgd_t *pgd) | 84 | static 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 | ||
455 | void 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 | |||
451 | static const char *ipi_types[NR_IPI] = { | 462 | static 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 | ||
461 | void show_ipi_list(struct seq_file *p, int prec) | 474 | void 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 | ||
531 | static DEFINE_PER_CPU(struct completion *, cpu_completion); | ||
532 | |||
533 | int register_ipi_completion(struct completion *completion, int cpu) | ||
534 | { | ||
535 | per_cpu(cpu_completion, cpu) = completion; | ||
536 | return IPI_COMPLETION; | ||
537 | } | ||
538 | |||
539 | static 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); |