diff options
Diffstat (limited to 'arch/powerpc/kernel/vdso64/gettimeofday.S')
-rw-r--r-- | arch/powerpc/kernel/vdso64/gettimeofday.S | 141 |
1 files changed, 76 insertions, 65 deletions
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S index c6401f9e37f1..262cd5857a56 100644 --- a/arch/powerpc/kernel/vdso64/gettimeofday.S +++ b/arch/powerpc/kernel/vdso64/gettimeofday.S | |||
@@ -75,90 +75,49 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) | |||
75 | 75 | ||
76 | mflr r12 /* r12 saves lr */ | 76 | mflr r12 /* r12 saves lr */ |
77 | .cfi_register lr,r12 | 77 | .cfi_register lr,r12 |
78 | mr r10,r3 /* r10 saves id */ | ||
79 | mr r11,r4 /* r11 saves tp */ | 78 | mr r11,r4 /* r11 saves tp */ |
80 | bl V_LOCAL_FUNC(__get_datapage) /* get data page */ | 79 | bl V_LOCAL_FUNC(__get_datapage) /* get data page */ |
81 | beq cr1,50f /* if monotonic -> jump there */ | 80 | 50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */ |
82 | 81 | bne cr1,80f /* if not monotonic, all done */ | |
83 | /* | ||
84 | * CLOCK_REALTIME | ||
85 | */ | ||
86 | |||
87 | bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ | ||
88 | |||
89 | lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ | ||
90 | ori r7,r7,16960 | ||
91 | rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ | ||
92 | rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ | ||
93 | std r5,TSPC64_TV_SEC(r11) /* store sec in tv */ | ||
94 | subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ | ||
95 | mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / | ||
96 | * XSEC_PER_SEC | ||
97 | */ | ||
98 | rldicl r0,r0,44,20 | ||
99 | mulli r0,r0,1000 /* nsec = usec * 1000 */ | ||
100 | std r0,TSPC64_TV_NSEC(r11) /* store nsec in tp */ | ||
101 | |||
102 | mtlr r12 | ||
103 | crclr cr0*4+so | ||
104 | li r3,0 | ||
105 | blr | ||
106 | 82 | ||
107 | /* | 83 | /* |
108 | * CLOCK_MONOTONIC | 84 | * CLOCK_MONOTONIC |
109 | */ | 85 | */ |
110 | 86 | ||
111 | 50: bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ | ||
112 | |||
113 | lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ | ||
114 | ori r7,r7,16960 | ||
115 | rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ | ||
116 | rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ | ||
117 | subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */ | ||
118 | mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) / | ||
119 | * XSEC_PER_SEC | ||
120 | */ | ||
121 | rldicl r6,r0,44,20 | ||
122 | mulli r6,r6,1000 /* nsec = usec * 1000 */ | ||
123 | |||
124 | /* now we must fixup using wall to monotonic. We need to snapshot | 87 | /* now we must fixup using wall to monotonic. We need to snapshot |
125 | * that value and do the counter trick again. Fortunately, we still | 88 | * that value and do the counter trick again. Fortunately, we still |
126 | * have the counter value in r8 that was returned by __do_get_xsec. | 89 | * have the counter value in r8 that was returned by __do_get_tspec. |
127 | * At this point, r5,r6 contain our sec/nsec values. | 90 | * At this point, r4,r5 contain our sec/nsec values. |
128 | * can be used | ||
129 | */ | 91 | */ |
130 | 92 | ||
131 | lwa r4,WTOM_CLOCK_SEC(r3) | 93 | lwa r6,WTOM_CLOCK_SEC(r3) |
132 | lwa r7,WTOM_CLOCK_NSEC(r3) | 94 | lwa r9,WTOM_CLOCK_NSEC(r3) |
133 | 95 | ||
134 | /* We now have our result in r4,r7. We create a fake dependency | 96 | /* We now have our result in r6,r9. We create a fake dependency |
135 | * on that result and re-check the counter | 97 | * on that result and re-check the counter |
136 | */ | 98 | */ |
137 | or r9,r4,r7 | 99 | or r0,r6,r9 |
138 | xor r0,r9,r9 | 100 | xor r0,r0,r0 |
139 | add r3,r3,r0 | 101 | add r3,r3,r0 |
140 | ld r0,CFG_TB_UPDATE_COUNT(r3) | 102 | ld r0,CFG_TB_UPDATE_COUNT(r3) |
141 | cmpld cr0,r0,r8 /* check if updated */ | 103 | cmpld cr0,r0,r8 /* check if updated */ |
142 | bne- 50b | 104 | bne- 50b |
143 | 105 | ||
144 | /* Calculate and store result. Note that this mimmics the C code, | 106 | /* Add wall->monotonic offset and check for overflow or underflow. |
145 | * which may cause funny results if nsec goes negative... is that | ||
146 | * possible at all ? | ||
147 | */ | 107 | */ |
148 | add r4,r4,r5 | 108 | add r4,r4,r6 |
149 | add r7,r7,r6 | 109 | add r5,r5,r9 |
150 | lis r9,NSEC_PER_SEC@h | 110 | cmpd cr0,r5,r7 |
151 | ori r9,r9,NSEC_PER_SEC@l | 111 | cmpdi cr1,r5,0 |
152 | cmpl cr0,r7,r9 | ||
153 | cmpli cr1,r7,0 | ||
154 | blt 1f | 112 | blt 1f |
155 | subf r7,r9,r7 | 113 | subf r5,r7,r5 |
156 | addi r4,r4,1 | 114 | addi r4,r4,1 |
157 | 1: bge cr1,1f | 115 | 1: bge cr1,80f |
158 | addi r4,r4,-1 | 116 | addi r4,r4,-1 |
159 | add r7,r7,r9 | 117 | add r5,r5,r7 |
160 | 1: std r4,TSPC64_TV_SEC(r11) | 118 | |
161 | std r7,TSPC64_TV_NSEC(r11) | 119 | 80: std r4,TSPC64_TV_SEC(r11) |
120 | std r5,TSPC64_TV_NSEC(r11) | ||
162 | 121 | ||
163 | mtlr r12 | 122 | mtlr r12 |
164 | crclr cr0*4+so | 123 | crclr cr0*4+so |
@@ -168,10 +127,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) | |||
168 | /* | 127 | /* |
169 | * syscall fallback | 128 | * syscall fallback |
170 | */ | 129 | */ |
171 | 98: | ||
172 | mtlr r12 | ||
173 | mr r3,r10 | ||
174 | mr r4,r11 | ||
175 | 99: | 130 | 99: |
176 | li r0,__NR_clock_gettime | 131 | li r0,__NR_clock_gettime |
177 | sc | 132 | sc |
@@ -253,3 +208,59 @@ V_FUNCTION_BEGIN(__do_get_xsec) | |||
253 | blr | 208 | blr |
254 | .cfi_endproc | 209 | .cfi_endproc |
255 | V_FUNCTION_END(__do_get_xsec) | 210 | V_FUNCTION_END(__do_get_xsec) |
211 | |||
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 | */ | ||
220 | V_FUNCTION_BEGIN(__do_get_tspec) | ||
221 | .cfi_startproc | ||
222 | /* check for update count & load values */ | ||
223 | 1: 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 | ||
266 | V_FUNCTION_END(__do_get_tspec) | ||