1/*
2 * Userland implementation of clock_gettime() for 32 bits processes in a
3 * s390 kernel for use in the vDSO
4 *
5 *  Copyright IBM Corp. 2008
6 *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License (version 2 only)
10 * as published by the Free Software Foundation.
11 */
12#include <asm/vdso.h>
13#include <asm/asm-offsets.h>
14#include <asm/unistd.h>
15
16	.text
17	.align 4
18	.globl __kernel_clock_gettime
19	.type  __kernel_clock_gettime,@function
20__kernel_clock_gettime:
21	.cfi_startproc
22	ahi	%r15,-16
23	basr	%r5,0
240:	al	%r5,21f-0b(%r5)			/* get &_vdso_data */
25	chi	%r2,__CLOCK_REALTIME_COARSE
26	je	10f
27	chi	%r2,__CLOCK_REALTIME
28	je	11f
29	chi	%r2,__CLOCK_MONOTONIC_COARSE
30	je	9f
31	chi	%r2,__CLOCK_MONOTONIC
32	jne	19f
33
34	/* CLOCK_MONOTONIC */
351:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
36	tml	%r4,0x0001			/* pending update ? loop */
37	jnz	1b
38	stcke	0(%r15)				/* Store TOD clock */
39	lm	%r0,%r1,1(%r15)
40	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
41	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
42	brc	3,2f
43	ahi	%r0,-1
442:	ms	%r0,__VDSO_TK_MULT(%r5)		/*  * tk->mult */
45	lr	%r2,%r0
46	l	%r0,__VDSO_TK_MULT(%r5)
47	ltr	%r1,%r1
48	mr	%r0,%r0
49	jnm	3f
50	a	%r0,__VDSO_TK_MULT(%r5)
513:	alr	%r0,%r2
52	al	%r0,__VDSO_WTOM_NSEC(%r5)
53	al	%r1,__VDSO_WTOM_NSEC+4(%r5)
54	brc	12,5f
55	ahi	%r0,1
565:	l	%r2,__VDSO_TK_SHIFT(%r5)	/* Timekeeper shift */
57	srdl	%r0,0(%r2)			/*  >> tk->shift */
58	l	%r2,__VDSO_WTOM_SEC+4(%r5)
59	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
60	jne	1b
61	basr	%r5,0
626:	ltr	%r0,%r0
63	jnz	7f
64	cl	%r1,20f-6b(%r5)
65	jl	8f
667:	ahi	%r2,1
67	sl	%r1,20f-6b(%r5)
68	brc	3,6b
69	ahi	%r0,-1
70	j	6b
718:	st	%r2,0(%r3)			/* store tp->tv_sec */
72	st	%r1,4(%r3)			/* store tp->tv_nsec */
73	lhi	%r2,0
74	ahi	%r15,16
75	br	%r14
76
77	/* CLOCK_MONOTONIC_COARSE */
789:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
79	tml	%r4,0x0001			/* pending update ? loop */
80	jnz	9b
81	l	%r2,__VDSO_WTOM_CRS_SEC+4(%r5)
82	l	%r1,__VDSO_WTOM_CRS_NSEC+4(%r5)
83	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
84	jne	9b
85	j	8b
86
87	/* CLOCK_REALTIME_COARSE */
8810:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
89	tml	%r4,0x0001			/* pending update ? loop */
90	jnz	10b
91	l	%r2,__VDSO_XTIME_CRS_SEC+4(%r5)
92	l	%r1,__VDSO_XTIME_CRS_NSEC+4(%r5)
93	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
94	jne	10b
95	j	17f
96
97	/* CLOCK_REALTIME */
9811:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
99	tml	%r4,0x0001			/* pending update ? loop */
100	jnz	11b
101	stcke	0(%r15)				/* Store TOD clock */
102	lm	%r0,%r1,1(%r15)
103	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
104	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
105	brc	3,12f
106	ahi	%r0,-1
10712:	ms	%r0,__VDSO_TK_MULT(%r5)		/*  * tk->mult */
108	lr	%r2,%r0
109	l	%r0,__VDSO_TK_MULT(%r5)
110	ltr	%r1,%r1
111	mr	%r0,%r0
112	jnm	13f
113	a	%r0,__VDSO_TK_MULT(%r5)
11413:	alr	%r0,%r2
115	al	%r0,__VDSO_XTIME_NSEC(%r5)	/*  + tk->xtime_nsec */
116	al	%r1,__VDSO_XTIME_NSEC+4(%r5)
117	brc	12,14f
118	ahi	%r0,1
11914:	l	%r2,__VDSO_TK_SHIFT(%r5)	/* Timekeeper shift */
120	srdl	%r0,0(%r2)			/*  >> tk->shift */
121	l	%r2,__VDSO_XTIME_SEC+4(%r5)
122	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
123	jne	11b
124	basr	%r5,0
12515:	ltr	%r0,%r0
126	jnz	16f
127	cl	%r1,20f-15b(%r5)
128	jl	17f
12916:	ahi	%r2,1
130	sl	%r1,20f-15b(%r5)
131	brc	3,15b
132	ahi	%r0,-1
133	j	15b
13417:	st	%r2,0(%r3)			/* store tp->tv_sec */
135	st	%r1,4(%r3)			/* store tp->tv_nsec */
136	lhi	%r2,0
137	ahi	%r15,16
138	br	%r14
139
140	/* Fallback to system call */
14119:	lhi	%r1,__NR_clock_gettime
142	svc	0
143	ahi	%r15,16
144	br	%r14
145
14620:	.long	1000000000
14721:	.long	_vdso_data - 0b
148	.cfi_endproc
149	.size	__kernel_clock_gettime,.-__kernel_clock_gettime
150