diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-04-14 15:36:29 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-04-14 15:37:27 +0200 |
commit | ab96e798cbd562a53edd802272e49a5100b29efb (patch) | |
tree | 4b3558bc97f5c2fc5c63789431deef79534e3bd3 /arch/s390/kernel/time.c | |
parent | [S390] add read_persistent_clock (diff) | |
download | linux-ab96e798cbd562a53edd802272e49a5100b29efb.tar.xz linux-ab96e798cbd562a53edd802272e49a5100b29efb.zip |
[S390] boot cputime accounting
Start the cpu time accounting very early to catch the cpu time spent
for the initial kernel setup. To make the output of /proc/uptime
match the sum of all cpu accounting values of the boot cpu reset
xtime and wall_to_monotonic to sane values based on the TOD clock.
The values set by timekeeping_init are off by up to a second.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/time.c')
-rw-r--r-- | arch/s390/kernel/time.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 369ff02c4ab2..6ded50dfa75a 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -253,32 +253,52 @@ void update_vsyscall_tz(void) */ void __init time_init(void) { + struct timespec ts; + unsigned long flags; + cycle_t now; + /* Reset time synchronization interfaces. */ etr_reset(); stp_reset(); - /* set xtime */ - tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &xtime); - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); - /* request the clock comparator external interrupt */ if (register_early_external_interrupt(0x1004, clock_comparator_interrupt, &ext_int_info_cc) != 0) panic("Couldn't request external interrupt 0x1004"); - if (clocksource_register(&clocksource_tod) != 0) - panic("Could not register TOD clock source"); - /* request the timing alert external interrupt */ if (register_early_external_interrupt(0x1406, timing_alert_interrupt, &ext_int_etr_cc) != 0) panic("Couldn't request external interrupt 0x1406"); + if (clocksource_register(&clocksource_tod) != 0) + panic("Could not register TOD clock source"); + + /* + * The TOD clock is an accurate clock. The xtime should be + * initialized in a way that the difference between TOD and + * xtime is reasonably small. Too bad that timekeeping_init + * sets xtime.tv_nsec to zero. In addition the clock source + * change from the jiffies clock source to the TOD clock + * source add another error of up to 1/HZ second. The same + * function sets wall_to_monotonic to a value that is too + * small for /proc/uptime to be accurate. + * Reset xtime and wall_to_monotonic to sane values. + */ + write_seqlock_irqsave(&xtime_lock, flags); + now = get_clock(); + tod_to_timeval(now - TOD_UNIX_EPOCH, &xtime); + clocksource_tod.cycle_last = now; + clocksource_tod.raw_time = xtime; + tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts); + set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec); + write_sequnlock_irqrestore(&xtime_lock, flags); + /* Enable TOD clock interrupts on the boot cpu. */ init_cpu_timer(); + /* Enable cpu timer interrupts on the boot cpu. */ vtime_init(); } |