75c7b6f3f6
On STP sync events the TOD clock will jump in time, either forward or backward. The TOD clocksource claims to be continuous but in case of an STP sync with a negative offset it is not. Subtract the offset injected by the STP sync check from the result of the TOD clocksource to make it continuous again. Add code to drift the offset towards zero with a fixed rate, steering 1 second in ~9 hours. Suggested-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
169 lines
4.0 KiB
ArmAsm
169 lines
4.0 KiB
ArmAsm
/*
|
|
* Userland implementation of clock_gettime() for 32 bits processes in a
|
|
* s390 kernel for use in the vDSO
|
|
*
|
|
* Copyright IBM Corp. 2008
|
|
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License (version 2 only)
|
|
* as published by the Free Software Foundation.
|
|
*/
|
|
#include <asm/vdso.h>
|
|
#include <asm/asm-offsets.h>
|
|
#include <asm/unistd.h>
|
|
|
|
.text
|
|
.align 4
|
|
.globl __kernel_clock_gettime
|
|
.type __kernel_clock_gettime,@function
|
|
__kernel_clock_gettime:
|
|
.cfi_startproc
|
|
ahi %r15,-16
|
|
basr %r5,0
|
|
0: al %r5,21f-0b(%r5) /* get &_vdso_data */
|
|
chi %r2,__CLOCK_REALTIME_COARSE
|
|
je 10f
|
|
chi %r2,__CLOCK_REALTIME
|
|
je 11f
|
|
chi %r2,__CLOCK_MONOTONIC_COARSE
|
|
je 9f
|
|
chi %r2,__CLOCK_MONOTONIC
|
|
jne 19f
|
|
|
|
/* CLOCK_MONOTONIC */
|
|
1: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */
|
|
tml %r4,0x0001 /* pending update ? loop */
|
|
jnz 1b
|
|
stcke 0(%r15) /* Store TOD clock */
|
|
lm %r0,%r1,1(%r15)
|
|
s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
|
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
|
brc 3,2f
|
|
ahi %r0,-1
|
|
2: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
|
lr %r2,%r0
|
|
l %r0,__VDSO_TK_MULT(%r5)
|
|
ltr %r1,%r1
|
|
mr %r0,%r0
|
|
jnm 3f
|
|
a %r0,__VDSO_TK_MULT(%r5)
|
|
3: alr %r0,%r2
|
|
al %r0,__VDSO_WTOM_NSEC(%r5)
|
|
al %r1,__VDSO_WTOM_NSEC+4(%r5)
|
|
brc 12,5f
|
|
ahi %r0,1
|
|
5: l %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
|
srdl %r0,0(%r2) /* >> tk->shift */
|
|
l %r2,__VDSO_WTOM_SEC+4(%r5)
|
|
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
|
jne 1b
|
|
basr %r5,0
|
|
6: ltr %r0,%r0
|
|
jnz 7f
|
|
cl %r1,20f-6b(%r5)
|
|
jl 8f
|
|
7: ahi %r2,1
|
|
sl %r1,20f-6b(%r5)
|
|
brc 3,6b
|
|
ahi %r0,-1
|
|
j 6b
|
|
8: st %r2,0(%r3) /* store tp->tv_sec */
|
|
st %r1,4(%r3) /* store tp->tv_nsec */
|
|
lhi %r2,0
|
|
ahi %r15,16
|
|
br %r14
|
|
|
|
/* CLOCK_MONOTONIC_COARSE */
|
|
9: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */
|
|
tml %r4,0x0001 /* pending update ? loop */
|
|
jnz 9b
|
|
l %r2,__VDSO_WTOM_CRS_SEC+4(%r5)
|
|
l %r1,__VDSO_WTOM_CRS_NSEC+4(%r5)
|
|
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
|
jne 9b
|
|
j 8b
|
|
|
|
/* CLOCK_REALTIME_COARSE */
|
|
10: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */
|
|
tml %r4,0x0001 /* pending update ? loop */
|
|
jnz 10b
|
|
l %r2,__VDSO_XTIME_CRS_SEC+4(%r5)
|
|
l %r1,__VDSO_XTIME_CRS_NSEC+4(%r5)
|
|
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
|
jne 10b
|
|
j 17f
|
|
|
|
/* CLOCK_REALTIME */
|
|
11: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */
|
|
tml %r4,0x0001 /* pending update ? loop */
|
|
jnz 11b
|
|
stcke 0(%r15) /* Store TOD clock */
|
|
lm %r0,%r1,__VDSO_TS_END(%r5) /* TOD steering end time */
|
|
s %r0,1(%r15) /* no - ts_steering_end */
|
|
sl %r1,5(%r15)
|
|
brc 3,22f
|
|
ahi %r0,-1
|
|
22: ltr %r0,%r0 /* past end of steering? */
|
|
jm 24f
|
|
srdl %r0,15 /* 1 per 2^16 */
|
|
tm __VDSO_TS_DIR+3(%r5),0x01 /* steering direction? */
|
|
jz 23f
|
|
lcr %r0,%r0 /* negative TOD offset */
|
|
lcr %r1,%r1
|
|
je 23f
|
|
ahi %r0,-1
|
|
23: a %r0,1(%r15) /* add TOD timestamp */
|
|
al %r1,5(%r15)
|
|
brc 12,25f
|
|
ahi %r0,1
|
|
j 25f
|
|
24: lm %r0,%r1,1(%r15) /* load TOD timestamp */
|
|
25: s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
|
|
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
|
|
brc 3,12f
|
|
ahi %r0,-1
|
|
12: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */
|
|
lr %r2,%r0
|
|
l %r0,__VDSO_TK_MULT(%r5)
|
|
ltr %r1,%r1
|
|
mr %r0,%r0
|
|
jnm 13f
|
|
a %r0,__VDSO_TK_MULT(%r5)
|
|
13: alr %r0,%r2
|
|
al %r0,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */
|
|
al %r1,__VDSO_XTIME_NSEC+4(%r5)
|
|
brc 12,14f
|
|
ahi %r0,1
|
|
14: l %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */
|
|
srdl %r0,0(%r2) /* >> tk->shift */
|
|
l %r2,__VDSO_XTIME_SEC+4(%r5)
|
|
cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */
|
|
jne 11b
|
|
basr %r5,0
|
|
15: ltr %r0,%r0
|
|
jnz 16f
|
|
cl %r1,20f-15b(%r5)
|
|
jl 17f
|
|
16: ahi %r2,1
|
|
sl %r1,20f-15b(%r5)
|
|
brc 3,15b
|
|
ahi %r0,-1
|
|
j 15b
|
|
17: st %r2,0(%r3) /* store tp->tv_sec */
|
|
st %r1,4(%r3) /* store tp->tv_nsec */
|
|
lhi %r2,0
|
|
ahi %r15,16
|
|
br %r14
|
|
|
|
/* Fallback to system call */
|
|
19: lhi %r1,__NR_clock_gettime
|
|
svc 0
|
|
ahi %r15,16
|
|
br %r14
|
|
|
|
20: .long 1000000000
|
|
21: .long _vdso_data - 0b
|
|
.cfi_endproc
|
|
.size __kernel_clock_gettime,.-__kernel_clock_gettime
|