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.c116
1 files changed, 8 insertions, 108 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 567dd7c3ac2a..2c42cd72d0f5 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -17,8 +17,7 @@
17 * 17 *
18 * TODO (not necessarily in this file): 18 * TODO (not necessarily in this file):
19 * - improve precision and reproducibility of timebase frequency 19 * - improve precision and reproducibility of timebase frequency
20 * measurement at boot time. (for iSeries, we calibrate the timebase 20 * measurement at boot time.
21 * against the Titan chip's clock.)
22 * - for astronomical applications: add a new function to get 21 * - for astronomical applications: add a new function to get
23 * non ambiguous timestamps even around leap seconds. This needs 22 * non ambiguous timestamps even around leap seconds. This needs
24 * a new timestamp format and a good name. 23 * a new timestamp format and a good name.
@@ -70,10 +69,6 @@
70#include <asm/vdso_datapage.h> 69#include <asm/vdso_datapage.h>
71#include <asm/firmware.h> 70#include <asm/firmware.h>
72#include <asm/cputime.h> 71#include <asm/cputime.h>
73#ifdef CONFIG_PPC_ISERIES
74#include <asm/iseries/it_lp_queue.h>
75#include <asm/iseries/hv_call_xm.h>
76#endif
77 72
78/* powerpc clocksource/clockevent code */ 73/* powerpc clocksource/clockevent code */
79 74
@@ -117,14 +112,6 @@ static struct clock_event_device decrementer_clockevent = {
117DEFINE_PER_CPU(u64, decrementers_next_tb); 112DEFINE_PER_CPU(u64, decrementers_next_tb);
118static DEFINE_PER_CPU(struct clock_event_device, decrementers); 113static DEFINE_PER_CPU(struct clock_event_device, decrementers);
119 114
120#ifdef CONFIG_PPC_ISERIES
121static unsigned long __initdata iSeries_recal_titan;
122static signed long __initdata iSeries_recal_tb;
123
124/* Forward declaration is only needed for iSereis compiles */
125static void __init clocksource_init(void);
126#endif
127
128#define XSEC_PER_SEC (1024*1024) 115#define XSEC_PER_SEC (1024*1024)
129 116
130#ifdef CONFIG_PPC64 117#ifdef CONFIG_PPC64
@@ -259,7 +246,6 @@ void accumulate_stolen_time(void)
259 u64 sst, ust; 246 u64 sst, ust;
260 247
261 u8 save_soft_enabled = local_paca->soft_enabled; 248 u8 save_soft_enabled = local_paca->soft_enabled;
262 u8 save_hard_enabled = local_paca->hard_enabled;
263 249
264 /* We are called early in the exception entry, before 250 /* We are called early in the exception entry, before
265 * soft/hard_enabled are sync'ed to the expected state 251 * soft/hard_enabled are sync'ed to the expected state
@@ -268,7 +254,6 @@ void accumulate_stolen_time(void)
268 * complain 254 * complain
269 */ 255 */
270 local_paca->soft_enabled = 0; 256 local_paca->soft_enabled = 0;
271 local_paca->hard_enabled = 0;
272 257
273 sst = scan_dispatch_log(local_paca->starttime_user); 258 sst = scan_dispatch_log(local_paca->starttime_user);
274 ust = scan_dispatch_log(local_paca->starttime); 259 ust = scan_dispatch_log(local_paca->starttime);
@@ -277,7 +262,6 @@ void accumulate_stolen_time(void)
277 local_paca->stolen_time += ust + sst; 262 local_paca->stolen_time += ust + sst;
278 263
279 local_paca->soft_enabled = save_soft_enabled; 264 local_paca->soft_enabled = save_soft_enabled;
280 local_paca->hard_enabled = save_hard_enabled;
281} 265}
282 266
283static inline u64 calculate_stolen_time(u64 stop_tb) 267static inline u64 calculate_stolen_time(u64 stop_tb)
@@ -426,74 +410,6 @@ unsigned long profile_pc(struct pt_regs *regs)
426EXPORT_SYMBOL(profile_pc); 410EXPORT_SYMBOL(profile_pc);
427#endif 411#endif
428 412
429#ifdef CONFIG_PPC_ISERIES
430
431/*
432 * This function recalibrates the timebase based on the 49-bit time-of-day
433 * value in the Titan chip. The Titan is much more accurate than the value
434 * returned by the service processor for the timebase frequency.
435 */
436
437static int __init iSeries_tb_recal(void)
438{
439 unsigned long titan, tb;
440
441 /* Make sure we only run on iSeries */
442 if (!firmware_has_feature(FW_FEATURE_ISERIES))
443 return -ENODEV;
444
445 tb = get_tb();
446 titan = HvCallXm_loadTod();
447 if ( iSeries_recal_titan ) {
448 unsigned long tb_ticks = tb - iSeries_recal_tb;
449 unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12;
450 unsigned long new_tb_ticks_per_sec = (tb_ticks * USEC_PER_SEC)/titan_usec;
451 unsigned long new_tb_ticks_per_jiffy =
452 DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ);
453 long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy;
454 char sign = '+';
455 /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */
456 new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ;
457
458 if ( tick_diff < 0 ) {
459 tick_diff = -tick_diff;
460 sign = '-';
461 }
462 if ( tick_diff ) {
463 if ( tick_diff < tb_ticks_per_jiffy/25 ) {
464 printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n",
465 new_tb_ticks_per_jiffy, sign, tick_diff );
466 tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
467 tb_ticks_per_sec = new_tb_ticks_per_sec;
468 calc_cputime_factors();
469 vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
470 setup_cputime_one_jiffy();
471 }
472 else {
473 printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
474 " new tb_ticks_per_jiffy = %lu\n"
475 " old tb_ticks_per_jiffy = %lu\n",
476 new_tb_ticks_per_jiffy, tb_ticks_per_jiffy );
477 }
478 }
479 }
480 iSeries_recal_titan = titan;
481 iSeries_recal_tb = tb;
482
483 /* Called here as now we know accurate values for the timebase */
484 clocksource_init();
485 return 0;
486}
487late_initcall(iSeries_tb_recal);
488
489/* Called from platform early init */
490void __init iSeries_time_init_early(void)
491{
492 iSeries_recal_tb = get_tb();
493 iSeries_recal_titan = HvCallXm_loadTod();
494}
495#endif /* CONFIG_PPC_ISERIES */
496
497#ifdef CONFIG_IRQ_WORK 413#ifdef CONFIG_IRQ_WORK
498 414
499/* 415/*
@@ -550,16 +466,6 @@ void arch_irq_work_raise(void)
550#endif /* CONFIG_IRQ_WORK */ 466#endif /* CONFIG_IRQ_WORK */
551 467
552/* 468/*
553 * For iSeries shared processors, we have to let the hypervisor
554 * set the hardware decrementer. We set a virtual decrementer
555 * in the lppaca and call the hypervisor if the virtual
556 * decrementer is less than the current value in the hardware
557 * decrementer. (almost always the new decrementer value will
558 * be greater than the current hardware decementer so the hypervisor
559 * call will not be needed)
560 */
561
562/*
563 * timer_interrupt - gets called when the decrementer overflows, 469 * timer_interrupt - gets called when the decrementer overflows,
564 * with interrupts disabled. 470 * with interrupts disabled.
565 */ 471 */
@@ -580,6 +486,11 @@ void timer_interrupt(struct pt_regs * regs)
580 if (!cpu_online(smp_processor_id())) 486 if (!cpu_online(smp_processor_id()))
581 return; 487 return;
582 488
489 /* Conditionally hard-enable interrupts now that the DEC has been
490 * bumped to its maximum value
491 */
492 may_hard_irq_enable();
493
583 trace_timer_interrupt_entry(regs); 494 trace_timer_interrupt_entry(regs);
584 495
585 __get_cpu_var(irq_stat).timer_irqs++; 496 __get_cpu_var(irq_stat).timer_irqs++;
@@ -597,20 +508,10 @@ void timer_interrupt(struct pt_regs * regs)
597 irq_work_run(); 508 irq_work_run();
598 } 509 }
599 510
600#ifdef CONFIG_PPC_ISERIES
601 if (firmware_has_feature(FW_FEATURE_ISERIES))
602 get_lppaca()->int_dword.fields.decr_int = 0;
603#endif
604
605 *next_tb = ~(u64)0; 511 *next_tb = ~(u64)0;
606 if (evt->event_handler) 512 if (evt->event_handler)
607 evt->event_handler(evt); 513 evt->event_handler(evt);
608 514
609#ifdef CONFIG_PPC_ISERIES
610 if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending())
611 process_hvlpevents();
612#endif
613
614#ifdef CONFIG_PPC64 515#ifdef CONFIG_PPC64
615 /* collect purr register values often, for accurate calculations */ 516 /* collect purr register values often, for accurate calculations */
616 if (firmware_has_feature(FW_FEATURE_SPLPAR)) { 517 if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
@@ -982,9 +883,8 @@ void __init time_init(void)
982 */ 883 */
983 start_cpu_decrementer(); 884 start_cpu_decrementer();
984 885
985 /* Register the clocksource, if we're not running on iSeries */ 886 /* Register the clocksource */
986 if (!firmware_has_feature(FW_FEATURE_ISERIES)) 887 clocksource_init();
987 clocksource_init();
988 888
989 init_decrementer_clockevent(); 889 init_decrementer_clockevent();
990} 890}