blob: 262cd5857a56dff9b53657e2a0872b7c769cc63e [file] [log] [blame]
Tony Breeds74609f42007-06-26 09:50:32 +10001/*
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +11002 * Userland implementation of gettimeofday() for 64 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 */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110013#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 r11,r3 /* r11 holds tv */
32 mr r10,r4 /* r10 holds tz */
33 bl V_LOCAL_FUNC(__get_datapage) /* get data page */
Will Schmidtfde937d2007-06-29 15:49:50 -050034 cmpldi r11,0 /* check if tv is NULL */
Tony Breeds74609f42007-06-26 09:50:32 +100035 beq 2f
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110036 bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
37 lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
38 ori r7,r7,16960
39 rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
40 rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
41 std r5,TVAL64_TV_SEC(r11) /* store sec in tv */
42 subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
43 mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
44 * XSEC_PER_SEC
45 */
46 rldicl r0,r0,44,20
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110047 std r0,TVAL64_TV_USEC(r11) /* store usec in tv */
Tony Breeds74609f42007-06-26 09:50:32 +1000482: cmpldi r10,0 /* check if tz is NULL */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110049 beq 1f
50 lwz r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */
51 lwz r5,CFG_TZ_DSTTIME(r3)
52 stw r4,TZONE_TZ_MINWEST(r10)
53 stw r5,TZONE_TZ_DSTTIME(r10)
541: mtlr r12
Benjamin Herrenschmidt5d66da32005-11-16 13:54:32 +110055 crclr cr0*4+so
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110056 li r3,0 /* always success */
57 blr
58 .cfi_endproc
59V_FUNCTION_END(__kernel_gettimeofday)
60
61
62/*
63 * Exact prototype of clock_gettime()
64 *
65 * int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp);
66 *
67 */
68V_FUNCTION_BEGIN(__kernel_clock_gettime)
69 .cfi_startproc
70 /* Check for supported clock IDs */
71 cmpwi cr0,r3,CLOCK_REALTIME
72 cmpwi cr1,r3,CLOCK_MONOTONIC
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +110073 cror cr0*4+eq,cr0*4+eq,cr1*4+eq
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110074 bne cr0,99f
75
76 mflr r12 /* r12 saves lr */
77 .cfi_register lr,r12
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110078 mr r11,r4 /* r11 saves tp */
79 bl V_LOCAL_FUNC(__get_datapage) /* get data page */
Paul Mackerras597bc5c2008-10-27 23:56:03 +00008050: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */
81 bne cr1,80f /* if not monotonic, all done */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110082
83 /*
84 * CLOCK_MONOTONIC
85 */
86
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110087 /* now we must fixup using wall to monotonic. We need to snapshot
88 * that value and do the counter trick again. Fortunately, we still
Paul Mackerras597bc5c2008-10-27 23:56:03 +000089 * have the counter value in r8 that was returned by __do_get_tspec.
90 * At this point, r4,r5 contain our sec/nsec values.
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110091 */
92
Paul Mackerras597bc5c2008-10-27 23:56:03 +000093 lwa r6,WTOM_CLOCK_SEC(r3)
94 lwa r9,WTOM_CLOCK_NSEC(r3)
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110095
Paul Mackerras597bc5c2008-10-27 23:56:03 +000096 /* We now have our result in r6,r9. We create a fake dependency
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110097 * on that result and re-check the counter
98 */
Paul Mackerras597bc5c2008-10-27 23:56:03 +000099 or r0,r6,r9
100 xor r0,r0,r0
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100101 add r3,r3,r0
102 ld r0,CFG_TB_UPDATE_COUNT(r3)
103 cmpld cr0,r0,r8 /* check if updated */
104 bne- 50b
105
Paul Mackerras597bc5c2008-10-27 23:56:03 +0000106 /* Add wall->monotonic offset and check for overflow or underflow.
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100107 */
Paul Mackerras597bc5c2008-10-27 23:56:03 +0000108 add r4,r4,r6
109 add r5,r5,r9
110 cmpd cr0,r5,r7
111 cmpdi cr1,r5,0
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100112 blt 1f
Paul Mackerras597bc5c2008-10-27 23:56:03 +0000113 subf r5,r7,r5
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100114 addi r4,r4,1
Paul Mackerras597bc5c2008-10-27 23:56:03 +00001151: bge cr1,80f
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +1100116 addi r4,r4,-1
Paul Mackerras597bc5c2008-10-27 23:56:03 +0000117 add r5,r5,r7
118
11980: std r4,TSPC64_TV_SEC(r11)
120 std r5,TSPC64_TV_NSEC(r11)
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100121
122 mtlr r12
Benjamin Herrenschmidt5d66da32005-11-16 13:54:32 +1100123 crclr cr0*4+so
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100124 li r3,0
125 blr
126
127 /*
128 * syscall fallback
129 */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +110013099:
131 li r0,__NR_clock_gettime
132 sc
133 blr
134 .cfi_endproc
135V_FUNCTION_END(__kernel_clock_gettime)
136
137
138/*
139 * Exact prototype of clock_getres()
140 *
141 * int __kernel_clock_getres(clockid_t clock_id, struct timespec *res);
142 *
143 */
144V_FUNCTION_BEGIN(__kernel_clock_getres)
145 .cfi_startproc
146 /* Check for supported clock IDs */
147 cmpwi cr0,r3,CLOCK_REALTIME
148 cmpwi cr1,r3,CLOCK_MONOTONIC
Benjamin Herrenschmidt0c37ec22005-11-14 14:55:58 +1100149 cror cr0*4+eq,cr0*4+eq,cr1*4+eq
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100150 bne cr0,99f
151
152 li r3,0
153 cmpli cr0,r4,0
Benjamin Herrenschmidt5d66da32005-11-16 13:54:32 +1100154 crclr cr0*4+so
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100155 beqlr
156 lis r5,CLOCK_REALTIME_RES@h
157 ori r5,r5,CLOCK_REALTIME_RES@l
158 std r3,TSPC64_TV_SEC(r4)
159 std r5,TSPC64_TV_NSEC(r4)
160 blr
161
162 /*
163 * syscall fallback
164 */
16599:
166 li r0,__NR_clock_getres
167 sc
168 blr
169 .cfi_endproc
170V_FUNCTION_END(__kernel_clock_getres)
171
172
173/*
174 * This is the core of gettimeofday(), it returns the xsec
175 * value in r4 and expects the datapage ptr (non clobbered)
176 * in r3. clobbers r0,r4,r5,r6,r7,r8
177 * When returning, r8 contains the counter value that can be reused
178 */
179V_FUNCTION_BEGIN(__do_get_xsec)
180 .cfi_startproc
181 /* check for update count & load values */
1821: ld r8,CFG_TB_UPDATE_COUNT(r3)
Benjamin Herrenschmidt634473d2006-02-26 08:09:00 +1100183 andi. r0,r8,1 /* pending update ? loop */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100184 bne- 1b
Benjamin Herrenschmidt634473d2006-02-26 08:09:00 +1100185 xor r0,r8,r8 /* create dependency */
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100186 add r3,r3,r0
187
Benjamin Herrenschmidt859deea2006-10-20 14:37:05 +1000188 /* Get TB & offset it. We use the MFTB macro which will generate
189 * workaround code for Cell.
190 */
191 MFTB(r7)
Benjamin Herrenschmidta7f290d2005-11-11 21:15:21 +1100192 ld r9,CFG_TB_ORIG_STAMP(r3)
193 subf r7,r9,r7
194
195 /* Scale result */
196 ld r5,CFG_TB_TO_XS(r3)
197 mulhdu r7,r7,r5
198
199 /* Add stamp since epoch */
200 ld r6,CFG_STAMP_XSEC(r3)
201 add r4,r6,r7
202
203 xor r0,r4,r4
204 add r3,r3,r0
205 ld r0,CFG_TB_UPDATE_COUNT(r3)
206 cmpld cr0,r0,r8 /* check if updated */
207 bne- 1b
208 blr
209 .cfi_endproc
210V_FUNCTION_END(__do_get_xsec)
Paul Mackerras597bc5c2008-10-27 23:56:03 +0000211
212/*
213 * This is the core of clock_gettime(), it returns the current
214 * time in seconds and nanoseconds in r4 and r5.
215 * It expects the datapage ptr in r3 and doesn't clobber it.
216 * It clobbers r0 and r6 and returns NSEC_PER_SEC in r7.
217 * On return, r8 contains the counter value that can be reused.
218 * This clobbers cr0 but not any other cr field.
219 */
220V_FUNCTION_BEGIN(__do_get_tspec)
221 .cfi_startproc
222 /* check for update count & load values */
2231: ld r8,CFG_TB_UPDATE_COUNT(r3)
224 andi. r0,r8,1 /* pending update ? loop */
225 bne- 1b
226 xor r0,r8,r8 /* create dependency */
227 add r3,r3,r0
228
229 /* Get TB & offset it. We use the MFTB macro which will generate
230 * workaround code for Cell.
231 */
232 MFTB(r7)
233 ld r9,CFG_TB_ORIG_STAMP(r3)
234 subf r7,r9,r7
235
236 /* Scale result */
237 ld r5,CFG_TB_TO_XS(r3)
238 sldi r7,r7,12 /* compute time since stamp_xtime */
239 mulhdu r6,r7,r5 /* in units of 2^-32 seconds */
240
241 /* Add stamp since epoch */
242 ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
243 ld r5,STAMP_XTIME+TSPC64_TV_NSEC(r3)
244 or r0,r4,r5
245 or r0,r0,r6
246 xor r0,r0,r0
247 add r3,r3,r0
248 ld r0,CFG_TB_UPDATE_COUNT(r3)
249 cmpld r0,r8 /* check if updated */
250 bne- 1b /* reload if so */
251
252 /* convert to seconds & nanoseconds and add to stamp */
253 lis r7,NSEC_PER_SEC@h
254 ori r7,r7,NSEC_PER_SEC@l
255 mulhwu r0,r6,r7 /* compute nanoseconds and */
256 srdi r6,r6,32 /* seconds since stamp_xtime */
257 clrldi r0,r0,32
258 add r5,r5,r0 /* add nanoseconds together */
259 cmpd r5,r7 /* overflow? */
260 add r4,r4,r6
261 bltlr /* all done if no overflow */
262 subf r5,r7,r5 /* if overflow, adjust */
263 addi r4,r4,1
264 blr
265 .cfi_endproc
266V_FUNCTION_END(__do_get_tspec)