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 | |
| 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>
| -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); |
