• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/arch/powerpc/kernel/vdso32/
1/*
2 * Userland implementation of gettimeofday() for 32 bits processes in a
3 * ppc64 kernel for use in the vDSO
4 *
5 * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org,
6 *                    IBM Corp.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#include <asm/processor.h>
14#include <asm/ppc_asm.h>
15#include <asm/vdso.h>
16#include <asm/asm-offsets.h>
17#include <asm/unistd.h>
18
19	.text
20/*
21 * Exact prototype of gettimeofday
22 *
23 * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
24 *
25 */
26V_FUNCTION_BEGIN(__kernel_gettimeofday)
27  .cfi_startproc
28	mflr	r12
29  .cfi_register lr,r12
30
31	mr	r10,r3			/* r10 saves tv */
32	mr	r11,r4			/* r11 saves tz */
33	bl	__get_datapage@local	/* get data page */
34	mr	r9, r3			/* datapage ptr in r9 */
35	cmplwi	r10,0			/* check if tv is NULL */
36	beq	3f
37	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
38	bne-	2f			/* out of line -> do syscall */
39
40	/* seconds are xsec >> 20 */
41	rlwinm	r5,r4,12,20,31
42	rlwimi	r5,r3,12,0,19
43	stw	r5,TVAL32_TV_SEC(r10)
44
45	/* get remaining xsec and convert to usec. we scale
46	 * up remaining xsec by 12 bits and get the top 32 bits
47	 * of the multiplication
48	 */
49	rlwinm	r5,r4,12,0,19
50	lis	r6,1000000@h
51	ori	r6,r6,1000000@l
52	mulhwu	r5,r5,r6
53	stw	r5,TVAL32_TV_USEC(r10)
54
553:	cmplwi	r11,0			/* check if tz is NULL */
56	beq	1f
57	lwz	r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */
58	lwz	r5,CFG_TZ_DSTTIME(r9)
59	stw	r4,TZONE_TZ_MINWEST(r11)
60	stw	r5,TZONE_TZ_DSTTIME(r11)
61
621:	mtlr	r12
63	crclr	cr0*4+so
64	li	r3,0
65	blr
66
672:
68	mtlr	r12
69	mr	r3,r10
70	mr	r4,r11
71	li	r0,__NR_gettimeofday
72	sc
73	blr
74  .cfi_endproc
75V_FUNCTION_END(__kernel_gettimeofday)
76
77/*
78 * Exact prototype of clock_gettime()
79 *
80 * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
81 *
82 */
83V_FUNCTION_BEGIN(__kernel_clock_gettime)
84  .cfi_startproc
85	/* Check for supported clock IDs */
86	cmpli	cr0,r3,CLOCK_REALTIME
87	cmpli	cr1,r3,CLOCK_MONOTONIC
88	cror	cr0*4+eq,cr0*4+eq,cr1*4+eq
89	bne	cr0,99f
90
91	mflr	r12			/* r12 saves lr */
92  .cfi_register lr,r12
93	mr	r10,r3			/* r10 saves id */
94	mr	r11,r4			/* r11 saves tp */
95	bl	__get_datapage@local	/* get data page */
96	mr	r9,r3			/* datapage ptr in r9 */
97	beq	cr1,50f			/* if monotonic -> jump there */
98
99	/*
100	 * CLOCK_REALTIME
101	 */
102
103	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
104	bne-	98f			/* out of line -> do syscall */
105
106	/* seconds are xsec >> 20 */
107	rlwinm	r5,r4,12,20,31
108	rlwimi	r5,r3,12,0,19
109	stw	r5,TSPC32_TV_SEC(r11)
110
111	/* get remaining xsec and convert to nsec. we scale
112	 * up remaining xsec by 12 bits and get the top 32 bits
113	 * of the multiplication, then we multiply by 1000
114	 */
115	rlwinm	r5,r4,12,0,19
116	lis	r6,1000000@h
117	ori	r6,r6,1000000@l
118	mulhwu	r5,r5,r6
119	mulli	r5,r5,1000
120	stw	r5,TSPC32_TV_NSEC(r11)
121	mtlr	r12
122	crclr	cr0*4+so
123	li	r3,0
124	blr
125
126	/*
127	 * CLOCK_MONOTONIC
128	 */
129
13050:	bl	__do_get_xsec@local	/* get xsec from tb & kernel */
131	bne-	98f			/* out of line -> do syscall */
132
133	/* seconds are xsec >> 20 */
134	rlwinm	r6,r4,12,20,31
135	rlwimi	r6,r3,12,0,19
136
137	/* get remaining xsec and convert to nsec. we scale
138	 * up remaining xsec by 12 bits and get the top 32 bits
139	 * of the multiplication, then we multiply by 1000
140	 */
141	rlwinm	r7,r4,12,0,19
142	lis	r5,1000000@h
143	ori	r5,r5,1000000@l
144	mulhwu	r7,r7,r5
145	mulli	r7,r7,1000
146
147	/* now we must fixup using wall to monotonic. We need to snapshot
148	 * that value and do the counter trick again. Fortunately, we still
149	 * have the counter value in r8 that was returned by __do_get_xsec.
150	 * At this point, r6,r7 contain our sec/nsec values, r3,r4 and r5
151	 * can be used
152	 */
153
154	lwz	r3,WTOM_CLOCK_SEC(r9)
155	lwz	r4,WTOM_CLOCK_NSEC(r9)
156
157	/* We now have our result in r3,r4. We create a fake dependency
158	 * on that result and re-check the counter
159	 */
160	or	r5,r4,r3
161	xor	r0,r5,r5
162	add	r9,r9,r0
163#ifdef CONFIG_PPC64
164	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
165#else
166	lwz	r0,(CFG_TB_UPDATE_COUNT)(r9)
167#endif
168        cmpl    cr0,r8,r0		/* check if updated */
169	bne-	50b
170
171	/* Calculate and store result. Note that this mimmics the C code,
172	 * which may cause funny results if nsec goes negative... is that
173	 * possible at all ?
174	 */
175	add	r3,r3,r6
176	add	r4,r4,r7
177	lis	r5,NSEC_PER_SEC@h
178	ori	r5,r5,NSEC_PER_SEC@l
179	cmpl	cr0,r4,r5
180	cmpli	cr1,r4,0
181	blt	1f
182	subf	r4,r5,r4
183	addi	r3,r3,1
1841:	bge	cr1,1f
185	addi	r3,r3,-1
186	add	r4,r4,r5
1871:	stw	r3,TSPC32_TV_SEC(r11)
188	stw	r4,TSPC32_TV_NSEC(r11)
189
190	mtlr	r12
191	crclr	cr0*4+so
192	li	r3,0
193	blr
194
195	/*
196	 * syscall fallback
197	 */
19898:
199	mtlr	r12
200	mr	r3,r10
201	mr	r4,r11
20299:
203	li	r0,__NR_clock_gettime
204	sc
205	blr
206  .cfi_endproc
207V_FUNCTION_END(__kernel_clock_gettime)
208
209
210/*
211 * Exact prototype of clock_getres()
212 *
213 * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
214 *
215 */
216V_FUNCTION_BEGIN(__kernel_clock_getres)
217  .cfi_startproc
218	/* Check for supported clock IDs */
219	cmpwi	cr0,r3,CLOCK_REALTIME
220	cmpwi	cr1,r3,CLOCK_MONOTONIC
221	cror	cr0*4+eq,cr0*4+eq,cr1*4+eq
222	bne	cr0,99f
223
224	li	r3,0
225	cmpli	cr0,r4,0
226	crclr	cr0*4+so
227	beqlr
228	lis	r5,CLOCK_REALTIME_RES@h
229	ori	r5,r5,CLOCK_REALTIME_RES@l
230	stw	r3,TSPC32_TV_SEC(r4)
231	stw	r5,TSPC32_TV_NSEC(r4)
232	blr
233
234	/*
235	 * syscall fallback
236	 */
23799:
238	li	r0,__NR_clock_getres
239	sc
240	blr
241  .cfi_endproc
242V_FUNCTION_END(__kernel_clock_getres)
243
244
245/*
246 * This is the core of gettimeofday() & friends, it returns the xsec
247 * value in r3 & r4 and expects the datapage ptr (non clobbered)
248 * in r9. clobbers r0,r4,r5,r6,r7,r8.
249 * When returning, r8 contains the counter value that can be reused
250 * by the monotonic clock implementation
251 */
252__do_get_xsec:
253  .cfi_startproc
254	/* Check for update count & load values. We use the low
255	 * order 32 bits of the update count
256	 */
257#ifdef CONFIG_PPC64
2581:	lwz	r8,(CFG_TB_UPDATE_COUNT+4)(r9)
259#else
2601:	lwz	r8,(CFG_TB_UPDATE_COUNT)(r9)
261#endif
262	andi.	r0,r8,1			/* pending update ? loop */
263	bne-	1b
264	xor	r0,r8,r8		/* create dependency */
265	add	r9,r9,r0
266
267	/* Load orig stamp (offset to TB) */
268	lwz	r5,CFG_TB_ORIG_STAMP(r9)
269	lwz	r6,(CFG_TB_ORIG_STAMP+4)(r9)
270
271	/* Get a stable TB value */
2722:	mftbu	r3
273	mftbl	r4
274	mftbu	r0
275	cmpl	cr0,r3,r0
276	bne-	2b
277
278	/* Substract tb orig stamp. If the high part is non-zero, we jump to
279	 * the slow path which call the syscall.
280	 * If it's ok, then we have our 32 bits tb_ticks value in r7
281	 */
282	subfc	r7,r6,r4
283	subfe.	r0,r5,r3
284	bne-	3f
285
286	/* Load scale factor & do multiplication */
287	lwz	r5,CFG_TB_TO_XS(r9)	/* load values */
288	lwz	r6,(CFG_TB_TO_XS+4)(r9)
289	mulhwu	r4,r7,r5
290	mulhwu	r6,r7,r6
291	mullw	r0,r7,r5
292	addc	r6,r6,r0
293
294	/* At this point, we have the scaled xsec value in r4 + XER:CA
295	 * we load & add the stamp since epoch
296	 */
297	lwz	r5,CFG_STAMP_XSEC(r9)
298	lwz	r6,(CFG_STAMP_XSEC+4)(r9)
299	adde	r4,r4,r6
300	addze	r3,r5
301
302	/* We now have our result in r3,r4. We create a fake dependency
303	 * on that result and re-check the counter
304	 */
305	or	r6,r4,r3
306	xor	r0,r6,r6
307	add	r9,r9,r0
308#ifdef CONFIG_PPC64
309	lwz	r0,(CFG_TB_UPDATE_COUNT+4)(r9)
310#else
311	lwz	r0,(CFG_TB_UPDATE_COUNT)(r9)
312#endif
313        cmpl    cr0,r8,r0		/* check if updated */
314	bne-	1b
315
316	/* Warning ! The caller expects CR:EQ to be set to indicate a
317	 * successful calculation (so it won't fallback to the syscall
318	 * method). We have overriden that CR bit in the counter check,
319	 * but fortunately, the loop exit condition _is_ CR:EQ set, so
320	 * we can exit safely here. If you change this code, be careful
321	 * of that side effect.
322	 */
3233:	blr
324  .cfi_endproc
325