diff options
Diffstat (limited to 'arch/arm/kernel/smp.c')
| -rw-r--r-- | arch/arm/kernel/smp.c | 131 |
1 files changed, 94 insertions, 37 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 6014dfd22af4..de885fd256c5 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
| @@ -22,16 +22,20 @@ | |||
| 22 | #include <linux/smp.h> | 22 | #include <linux/smp.h> |
| 23 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
| 24 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
| 25 | #include <linux/percpu.h> | ||
| 26 | #include <linux/clockchips.h> | ||
| 25 | 27 | ||
| 26 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
| 27 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
| 28 | #include <asm/cpu.h> | 30 | #include <asm/cpu.h> |
| 31 | #include <asm/cputype.h> | ||
| 29 | #include <asm/mmu_context.h> | 32 | #include <asm/mmu_context.h> |
| 30 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
| 31 | #include <asm/pgalloc.h> | 34 | #include <asm/pgalloc.h> |
| 32 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
| 33 | #include <asm/tlbflush.h> | 36 | #include <asm/tlbflush.h> |
| 34 | #include <asm/ptrace.h> | 37 | #include <asm/ptrace.h> |
| 38 | #include <asm/localtimer.h> | ||
| 35 | 39 | ||
| 36 | /* | 40 | /* |
| 37 | * as from 2.5, kernels no longer have an init_tasks structure | 41 | * as from 2.5, kernels no longer have an init_tasks structure |
| @@ -163,7 +167,7 @@ int __cpuexit __cpu_disable(void) | |||
| 163 | * Take this CPU offline. Once we clear this, we can't return, | 167 | * Take this CPU offline. Once we clear this, we can't return, |
| 164 | * and we must not schedule until we're ready to give up the cpu. | 168 | * and we must not schedule until we're ready to give up the cpu. |
| 165 | */ | 169 | */ |
| 166 | cpu_clear(cpu, cpu_online_map); | 170 | set_cpu_online(cpu, false); |
| 167 | 171 | ||
| 168 | /* | 172 | /* |
| 169 | * OK - migrate IRQs away from this CPU | 173 | * OK - migrate IRQs away from this CPU |
| @@ -274,9 +278,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
| 274 | local_fiq_enable(); | 278 | local_fiq_enable(); |
| 275 | 279 | ||
| 276 | /* | 280 | /* |
| 277 | * Setup local timer for this CPU. | 281 | * Setup the percpu timer for this CPU. |
| 278 | */ | 282 | */ |
| 279 | local_timer_setup(); | 283 | percpu_timer_setup(); |
| 280 | 284 | ||
| 281 | calibrate_delay(); | 285 | calibrate_delay(); |
| 282 | 286 | ||
| @@ -285,7 +289,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
| 285 | /* | 289 | /* |
| 286 | * OK, now it's safe to let the boot CPU continue | 290 | * OK, now it's safe to let the boot CPU continue |
| 287 | */ | 291 | */ |
| 288 | cpu_set(cpu, cpu_online_map); | 292 | set_cpu_online(cpu, true); |
| 289 | 293 | ||
| 290 | /* | 294 | /* |
| 291 | * OK, it's off to the idle thread for us | 295 | * OK, it's off to the idle thread for us |
| @@ -383,10 +387,16 @@ void show_local_irqs(struct seq_file *p) | |||
| 383 | seq_putc(p, '\n'); | 387 | seq_putc(p, '\n'); |
| 384 | } | 388 | } |
| 385 | 389 | ||
| 390 | /* | ||
| 391 | * Timer (local or broadcast) support | ||
| 392 | */ | ||
| 393 | static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); | ||
| 394 | |||
| 386 | static void ipi_timer(void) | 395 | static void ipi_timer(void) |
| 387 | { | 396 | { |
| 397 | struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); | ||
| 388 | irq_enter(); | 398 | irq_enter(); |
| 389 | local_timer_interrupt(); | 399 | evt->event_handler(evt); |
| 390 | irq_exit(); | 400 | irq_exit(); |
| 391 | } | 401 | } |
| 392 | 402 | ||
| @@ -405,6 +415,42 @@ asmlinkage void __exception do_local_timer(struct pt_regs *regs) | |||
| 405 | } | 415 | } |
| 406 | #endif | 416 | #endif |
| 407 | 417 | ||
| 418 | #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST | ||
| 419 | static void smp_timer_broadcast(const struct cpumask *mask) | ||
| 420 | { | ||
| 421 | send_ipi_message(mask, IPI_TIMER); | ||
| 422 | } | ||
| 423 | |||
| 424 | static void broadcast_timer_set_mode(enum clock_event_mode mode, | ||
| 425 | struct clock_event_device *evt) | ||
| 426 | { | ||
| 427 | } | ||
| 428 | |||
| 429 | static void local_timer_setup(struct clock_event_device *evt) | ||
| 430 | { | ||
| 431 | evt->name = "dummy_timer"; | ||
| 432 | evt->features = CLOCK_EVT_FEAT_ONESHOT | | ||
| 433 | CLOCK_EVT_FEAT_PERIODIC | | ||
| 434 | CLOCK_EVT_FEAT_DUMMY; | ||
| 435 | evt->rating = 400; | ||
| 436 | evt->mult = 1; | ||
| 437 | evt->set_mode = broadcast_timer_set_mode; | ||
| 438 | evt->broadcast = smp_timer_broadcast; | ||
| 439 | |||
| 440 | clockevents_register_device(evt); | ||
| 441 | } | ||
| 442 | #endif | ||
| 443 | |||
| 444 | void __cpuinit percpu_timer_setup(void) | ||
| 445 | { | ||
| 446 | unsigned int cpu = smp_processor_id(); | ||
| 447 | struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); | ||
| 448 | |||
| 449 | evt->cpumask = cpumask_of(cpu); | ||
| 450 | |||
| 451 | local_timer_setup(evt); | ||
| 452 | } | ||
| 453 | |||
| 408 | static DEFINE_SPINLOCK(stop_lock); | 454 | static DEFINE_SPINLOCK(stop_lock); |
| 409 | 455 | ||
| 410 | /* | 456 | /* |
| @@ -417,7 +463,7 @@ static void ipi_cpu_stop(unsigned int cpu) | |||
| 417 | dump_stack(); | 463 | dump_stack(); |
| 418 | spin_unlock(&stop_lock); | 464 | spin_unlock(&stop_lock); |
| 419 | 465 | ||
| 420 | cpu_clear(cpu, cpu_online_map); | 466 | set_cpu_online(cpu, false); |
| 421 | 467 | ||
| 422 | local_fiq_disable(); | 468 | local_fiq_disable(); |
| 423 | local_irq_disable(); | 469 | local_irq_disable(); |
| @@ -501,11 +547,6 @@ void smp_send_reschedule(int cpu) | |||
| 501 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); | 547 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); |
| 502 | } | 548 | } |
| 503 | 549 | ||
| 504 | void smp_timer_broadcast(const struct cpumask *mask) | ||
| 505 | { | ||
| 506 | send_ipi_message(mask, IPI_TIMER); | ||
| 507 | } | ||
| 508 | |||
| 509 | void smp_send_stop(void) | 550 | void smp_send_stop(void) |
| 510 | { | 551 | { |
| 511 | cpumask_t mask = cpu_online_map; | 552 | cpumask_t mask = cpu_online_map; |
| @@ -545,6 +586,12 @@ struct tlb_args { | |||
| 545 | unsigned long ta_end; | 586 | unsigned long ta_end; |
| 546 | }; | 587 | }; |
| 547 | 588 | ||
| 589 | /* all SMP configurations have the extended CPUID registers */ | ||
| 590 | static inline int tlb_ops_need_broadcast(void) | ||
| 591 | { | ||
| 592 | return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2; | ||
| 593 | } | ||
| 594 | |||
| 548 | static inline void ipi_flush_tlb_all(void *ignored) | 595 | static inline void ipi_flush_tlb_all(void *ignored) |
| 549 | { | 596 | { |
| 550 | local_flush_tlb_all(); | 597 | local_flush_tlb_all(); |
| @@ -587,51 +634,61 @@ static inline void ipi_flush_tlb_kernel_range(void *arg) | |||
| 587 | 634 | ||
| 588 | void flush_tlb_all(void) | 635 | void flush_tlb_all(void) |
| 589 | { | 636 | { |
| 590 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | 637 | if (tlb_ops_need_broadcast()) |
| 638 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | ||
| 639 | else | ||
| 640 | local_flush_tlb_all(); | ||
| 591 | } | 641 | } |
| 592 | 642 | ||
| 593 | void flush_tlb_mm(struct mm_struct *mm) | 643 | void flush_tlb_mm(struct mm_struct *mm) |
| 594 | { | 644 | { |
| 595 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); | 645 | if (tlb_ops_need_broadcast()) |
| 646 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); | ||
| 647 | else | ||
| 648 | local_flush_tlb_mm(mm); | ||
| 596 | } | 649 | } |
| 597 | 650 | ||
| 598 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | 651 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) |
| 599 | { | 652 | { |
| 600 | struct tlb_args ta; | 653 | if (tlb_ops_need_broadcast()) { |
| 601 | 654 | struct tlb_args ta; | |
| 602 | ta.ta_vma = vma; | 655 | ta.ta_vma = vma; |
| 603 | ta.ta_start = uaddr; | 656 | ta.ta_start = uaddr; |
| 604 | 657 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); | |
| 605 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); | 658 | } else |
| 659 | local_flush_tlb_page(vma, uaddr); | ||
| 606 | } | 660 | } |
| 607 | 661 | ||
| 608 | void flush_tlb_kernel_page(unsigned long kaddr) | 662 | void flush_tlb_kernel_page(unsigned long kaddr) |
| 609 | { | 663 | { |
| 610 | struct tlb_args ta; | 664 | if (tlb_ops_need_broadcast()) { |
| 611 | 665 | struct tlb_args ta; | |
| 612 | ta.ta_start = kaddr; | 666 | ta.ta_start = kaddr; |
| 613 | 667 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | |
| 614 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | 668 | } else |
| 669 | local_flush_tlb_kernel_page(kaddr); | ||
| 615 | } | 670 | } |
| 616 | 671 | ||
| 617 | void flush_tlb_range(struct vm_area_struct *vma, | 672 | void flush_tlb_range(struct vm_area_struct *vma, |
| 618 | unsigned long start, unsigned long end) | 673 | unsigned long start, unsigned long end) |
| 619 | { | 674 | { |
| 620 | struct tlb_args ta; | 675 | if (tlb_ops_need_broadcast()) { |
| 621 | 676 | struct tlb_args ta; | |
| 622 | ta.ta_vma = vma; | 677 | ta.ta_vma = vma; |
| 623 | ta.ta_start = start; | 678 | ta.ta_start = start; |
| 624 | ta.ta_end = end; | 679 | ta.ta_end = end; |
| 625 | 680 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); | |
| 626 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); | 681 | } else |
| 682 | local_flush_tlb_range(vma, start, end); | ||
| 627 | } | 683 | } |
| 628 | 684 | ||
| 629 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | 685 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) |
| 630 | { | 686 | { |
| 631 | struct tlb_args ta; | 687 | if (tlb_ops_need_broadcast()) { |
| 632 | 688 | struct tlb_args ta; | |
| 633 | ta.ta_start = start; | 689 | ta.ta_start = start; |
| 634 | ta.ta_end = end; | 690 | ta.ta_end = end; |
| 635 | 691 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | |
| 636 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | 692 | } else |
| 693 | local_flush_tlb_kernel_range(start, end); | ||
| 637 | } | 694 | } |
