aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r--arch/powerpc/kernel/time.c90
1 files changed, 54 insertions, 36 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index b3dab20acf34..122a580f7322 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -42,6 +42,7 @@
42#include <linux/timex.h> 42#include <linux/timex.h>
43#include <linux/kernel_stat.h> 43#include <linux/kernel_stat.h>
44#include <linux/time.h> 44#include <linux/time.h>
45#include <linux/clockchips.h>
45#include <linux/init.h> 46#include <linux/init.h>
46#include <linux/profile.h> 47#include <linux/profile.h>
47#include <linux/cpu.h> 48#include <linux/cpu.h>
@@ -106,7 +107,7 @@ struct clock_event_device decrementer_clockevent = {
106 .irq = 0, 107 .irq = 0,
107 .set_next_event = decrementer_set_next_event, 108 .set_next_event = decrementer_set_next_event,
108 .set_mode = decrementer_set_mode, 109 .set_mode = decrementer_set_mode,
109 .features = CLOCK_EVT_FEAT_ONESHOT, 110 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
110}; 111};
111EXPORT_SYMBOL(decrementer_clockevent); 112EXPORT_SYMBOL(decrementer_clockevent);
112 113
@@ -478,6 +479,47 @@ void arch_irq_work_raise(void)
478 479
479#endif /* CONFIG_IRQ_WORK */ 480#endif /* CONFIG_IRQ_WORK */
480 481
482void __timer_interrupt(void)
483{
484 struct pt_regs *regs = get_irq_regs();
485 u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
486 struct clock_event_device *evt = &__get_cpu_var(decrementers);
487 u64 now;
488
489 trace_timer_interrupt_entry(regs);
490
491 if (test_irq_work_pending()) {
492 clear_irq_work_pending();
493 irq_work_run();
494 }
495
496 now = get_tb_or_rtc();
497 if (now >= *next_tb) {
498 *next_tb = ~(u64)0;
499 if (evt->event_handler)
500 evt->event_handler(evt);
501 __get_cpu_var(irq_stat).timer_irqs_event++;
502 } else {
503 now = *next_tb - now;
504 if (now <= DECREMENTER_MAX)
505 set_dec((int)now);
506 /* We may have raced with new irq work */
507 if (test_irq_work_pending())
508 set_dec(1);
509 __get_cpu_var(irq_stat).timer_irqs_others++;
510 }
511
512#ifdef CONFIG_PPC64
513 /* collect purr register values often, for accurate calculations */
514 if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
515 struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
516 cu->current_tb = mfspr(SPRN_PURR);
517 }
518#endif
519
520 trace_timer_interrupt_exit(regs);
521}
522
481/* 523/*
482 * timer_interrupt - gets called when the decrementer overflows, 524 * timer_interrupt - gets called when the decrementer overflows,
483 * with interrupts disabled. 525 * with interrupts disabled.
@@ -486,8 +528,6 @@ void timer_interrupt(struct pt_regs * regs)
486{ 528{
487 struct pt_regs *old_regs; 529 struct pt_regs *old_regs;
488 u64 *next_tb = &__get_cpu_var(decrementers_next_tb); 530 u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
489 struct clock_event_device *evt = &__get_cpu_var(decrementers);
490 u64 now;
491 531
492 /* Ensure a positive value is written to the decrementer, or else 532 /* Ensure a positive value is written to the decrementer, or else
493 * some CPUs will continue to take decrementer exceptions. 533 * some CPUs will continue to take decrementer exceptions.
@@ -519,39 +559,7 @@ void timer_interrupt(struct pt_regs * regs)
519 old_regs = set_irq_regs(regs); 559 old_regs = set_irq_regs(regs);
520 irq_enter(); 560 irq_enter();
521 561
522 trace_timer_interrupt_entry(regs); 562 __timer_interrupt();
523
524 if (test_irq_work_pending()) {
525 clear_irq_work_pending();
526 irq_work_run();
527 }
528
529 now = get_tb_or_rtc();
530 if (now >= *next_tb) {
531 *next_tb = ~(u64)0;
532 if (evt->event_handler)
533 evt->event_handler(evt);
534 __get_cpu_var(irq_stat).timer_irqs_event++;
535 } else {
536 now = *next_tb - now;
537 if (now <= DECREMENTER_MAX)
538 set_dec((int)now);
539 /* We may have raced with new irq work */
540 if (test_irq_work_pending())
541 set_dec(1);
542 __get_cpu_var(irq_stat).timer_irqs_others++;
543 }
544
545#ifdef CONFIG_PPC64
546 /* collect purr register values often, for accurate calculations */
547 if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
548 struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
549 cu->current_tb = mfspr(SPRN_PURR);
550 }
551#endif
552
553 trace_timer_interrupt_exit(regs);
554
555 irq_exit(); 563 irq_exit();
556 set_irq_regs(old_regs); 564 set_irq_regs(old_regs);
557} 565}
@@ -825,6 +833,15 @@ static void decrementer_set_mode(enum clock_event_mode mode,
825 decrementer_set_next_event(DECREMENTER_MAX, dev); 833 decrementer_set_next_event(DECREMENTER_MAX, dev);
826} 834}
827 835
836/* Interrupt handler for the timer broadcast IPI */
837void tick_broadcast_ipi_handler(void)
838{
839 u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
840
841 *next_tb = get_tb_or_rtc();
842 __timer_interrupt();
843}
844
828static void register_decrementer_clockevent(int cpu) 845static void register_decrementer_clockevent(int cpu)
829{ 846{
830 struct clock_event_device *dec = &per_cpu(decrementers, cpu); 847 struct clock_event_device *dec = &per_cpu(decrementers, cpu);
@@ -928,6 +945,7 @@ void __init time_init(void)
928 clocksource_init(); 945 clocksource_init();
929 946
930 init_decrementer_clockevent(); 947 init_decrementer_clockevent();
948 tick_setup_hrtimer_broadcast();
931} 949}
932 950
933 951