diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-04-14 09:36:29 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-04-14 09:37:27 -0400 |
commit | ab96e798cbd562a53edd802272e49a5100b29efb (patch) | |
tree | 4b3558bc97f5c2fc5c63789431deef79534e3bd3 /arch/s390 | |
parent | b6112ccbff5ec580d46b584ecc3c3a773b830da2 (diff) |
[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')
-rw-r--r-- | arch/s390/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 8 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 36 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 8 |
4 files changed, 43 insertions, 17 deletions
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 16f8975325ed..bba14494ee00 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S | |||
@@ -473,7 +473,10 @@ startup:basr %r13,0 # get base | |||
473 | xc 0x300(256),0x300 | 473 | xc 0x300(256),0x300 |
474 | l %r1,5f-.LPG0(%r13) | 474 | l %r1,5f-.LPG0(%r13) |
475 | stck 0(%r1) | 475 | stck 0(%r1) |
476 | 476 | spt 6f-.LPG0(%r13) | |
477 | mvc __LC_LAST_UPDATE_CLOCK(8),0(%r1) | ||
478 | mvc __LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13) | ||
479 | mvc __LC_EXIT_TIMER(8),5f-.LPG0(%r13) | ||
477 | #ifndef CONFIG_MARCH_G5 | 480 | #ifndef CONFIG_MARCH_G5 |
478 | # check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10} | 481 | # check processor version against MARCH_{G5,Z900,Z990,Z9_109,Z10} |
479 | stidp __LC_CPUID # store cpuid | 482 | stidp __LC_CPUID # store cpuid |
@@ -500,8 +503,11 @@ startup:basr %r13,0 # get base | |||
500 | 503 | ||
501 | l %r13,4f-.LPG0(%r13) | 504 | l %r13,4f-.LPG0(%r13) |
502 | b 0(%r13) | 505 | b 0(%r13) |
506 | .align 4 | ||
503 | 4: .long startup_continue | 507 | 4: .long startup_continue |
504 | 5: .long sched_clock_base_cc | 508 | 5: .long sched_clock_base_cc |
509 | .align 8 | ||
510 | 6: .long 0x7fffffff,0xffffffff | ||
505 | 511 | ||
506 | # | 512 | # |
507 | # params at 10400 (setup.h) | 513 | # params at 10400 (setup.h) |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 163bdfe5a6be..7402b6a39ead 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -434,6 +434,14 @@ setup_lowcore(void) | |||
434 | #else | 434 | #else |
435 | lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; | 435 | lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; |
436 | #endif | 436 | #endif |
437 | lc->sync_enter_timer = S390_lowcore.sync_enter_timer; | ||
438 | lc->async_enter_timer = S390_lowcore.async_enter_timer; | ||
439 | lc->exit_timer = S390_lowcore.exit_timer; | ||
440 | lc->user_timer = S390_lowcore.user_timer; | ||
441 | lc->system_timer = S390_lowcore.system_timer; | ||
442 | lc->steal_timer = S390_lowcore.steal_timer; | ||
443 | lc->last_update_timer = S390_lowcore.last_update_timer; | ||
444 | lc->last_update_clock = S390_lowcore.last_update_clock; | ||
437 | set_prefix((u32)(unsigned long) lc); | 445 | set_prefix((u32)(unsigned long) lc); |
438 | lowcore_ptr[0] = lc; | 446 | lowcore_ptr[0] = lc; |
439 | } | 447 | } |
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) | |||
253 | */ | 253 | */ |
254 | void __init time_init(void) | 254 | void __init time_init(void) |
255 | { | 255 | { |
256 | struct timespec ts; | ||
257 | unsigned long flags; | ||
258 | cycle_t now; | ||
259 | |||
256 | /* Reset time synchronization interfaces. */ | 260 | /* Reset time synchronization interfaces. */ |
257 | etr_reset(); | 261 | etr_reset(); |
258 | stp_reset(); | 262 | stp_reset(); |
259 | 263 | ||
260 | /* set xtime */ | ||
261 | tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &xtime); | ||
262 | set_normalized_timespec(&wall_to_monotonic, | ||
263 | -xtime.tv_sec, -xtime.tv_nsec); | ||
264 | |||
265 | /* request the clock comparator external interrupt */ | 264 | /* request the clock comparator external interrupt */ |
266 | if (register_early_external_interrupt(0x1004, | 265 | if (register_early_external_interrupt(0x1004, |
267 | clock_comparator_interrupt, | 266 | clock_comparator_interrupt, |
268 | &ext_int_info_cc) != 0) | 267 | &ext_int_info_cc) != 0) |
269 | panic("Couldn't request external interrupt 0x1004"); | 268 | panic("Couldn't request external interrupt 0x1004"); |
270 | 269 | ||
271 | if (clocksource_register(&clocksource_tod) != 0) | ||
272 | panic("Could not register TOD clock source"); | ||
273 | |||
274 | /* request the timing alert external interrupt */ | 270 | /* request the timing alert external interrupt */ |
275 | if (register_early_external_interrupt(0x1406, | 271 | if (register_early_external_interrupt(0x1406, |
276 | timing_alert_interrupt, | 272 | timing_alert_interrupt, |
277 | &ext_int_etr_cc) != 0) | 273 | &ext_int_etr_cc) != 0) |
278 | panic("Couldn't request external interrupt 0x1406"); | 274 | panic("Couldn't request external interrupt 0x1406"); |
279 | 275 | ||
276 | if (clocksource_register(&clocksource_tod) != 0) | ||
277 | panic("Could not register TOD clock source"); | ||
278 | |||
279 | /* | ||
280 | * The TOD clock is an accurate clock. The xtime should be | ||
281 | * initialized in a way that the difference between TOD and | ||
282 | * xtime is reasonably small. Too bad that timekeeping_init | ||
283 | * sets xtime.tv_nsec to zero. In addition the clock source | ||
284 | * change from the jiffies clock source to the TOD clock | ||
285 | * source add another error of up to 1/HZ second. The same | ||
286 | * function sets wall_to_monotonic to a value that is too | ||
287 | * small for /proc/uptime to be accurate. | ||
288 | * Reset xtime and wall_to_monotonic to sane values. | ||
289 | */ | ||
290 | write_seqlock_irqsave(&xtime_lock, flags); | ||
291 | now = get_clock(); | ||
292 | tod_to_timeval(now - TOD_UNIX_EPOCH, &xtime); | ||
293 | clocksource_tod.cycle_last = now; | ||
294 | clocksource_tod.raw_time = xtime; | ||
295 | tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts); | ||
296 | set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec); | ||
297 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
298 | |||
280 | /* Enable TOD clock interrupts on the boot cpu. */ | 299 | /* Enable TOD clock interrupts on the boot cpu. */ |
281 | init_cpu_timer(); | 300 | init_cpu_timer(); |
301 | |||
282 | /* Enable cpu timer interrupts on the boot cpu. */ | 302 | /* Enable cpu timer interrupts on the boot cpu. */ |
283 | vtime_init(); | 303 | vtime_init(); |
284 | } | 304 | } |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index c0870a61f90f..38ea92ff04f9 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -527,16 +527,8 @@ EXPORT_SYMBOL(del_virt_timer); | |||
527 | */ | 527 | */ |
528 | void init_cpu_vtimer(void) | 528 | void init_cpu_vtimer(void) |
529 | { | 529 | { |
530 | struct thread_info *ti = current_thread_info(); | ||
531 | struct vtimer_queue *vq; | 530 | struct vtimer_queue *vq; |
532 | 531 | ||
533 | S390_lowcore.user_timer = ti->user_timer; | ||
534 | S390_lowcore.system_timer = ti->system_timer; | ||
535 | |||
536 | /* kick the virtual timer */ | ||
537 | asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); | ||
538 | asm volatile ("STPT %0" : "=m" (S390_lowcore.last_update_timer)); | ||
539 | |||
540 | /* initialize per cpu vtimer structure */ | 532 | /* initialize per cpu vtimer structure */ |
541 | vq = &__get_cpu_var(virt_cpu_timer); | 533 | vq = &__get_cpu_var(virt_cpu_timer); |
542 | INIT_LIST_HEAD(&vq->list); | 534 | INIT_LIST_HEAD(&vq->list); |