diff options
author | Mike Travis <travis@sgi.com> | 2008-12-31 20:34:16 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-03 12:53:31 -0500 |
commit | 7eb19553369c46cc1fa64caf120cbcab1b597f7c (patch) | |
tree | ef1a3beae706b9497c845d0a2557ceb4d2754998 /arch/powerpc/kernel/vdso32/gettimeofday.S | |
parent | 6092848a2a23b660150a38bc06f59d75838d70c8 (diff) | |
parent | 8c384cdee3e04d6194a2c2b192b624754f990835 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-cpumask into merge-rr-cpumask
Conflicts:
arch/x86/kernel/io_apic.c
kernel/rcuclassic.c
kernel/sched.c
kernel/time/tick-sched.c
Signed-off-by: Mike Travis <travis@sgi.com>
[ mingo@elte.hu: backmerged typo fix for io_apic.c ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/powerpc/kernel/vdso32/gettimeofday.S')
-rw-r--r-- | arch/powerpc/kernel/vdso32/gettimeofday.S | 208 |
1 files changed, 125 insertions, 83 deletions
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S index 72ca26df457e..ee038d4bf252 100644 --- a/arch/powerpc/kernel/vdso32/gettimeofday.S +++ b/arch/powerpc/kernel/vdso32/gettimeofday.S | |||
@@ -16,6 +16,13 @@ | |||
16 | #include <asm/asm-offsets.h> | 16 | #include <asm/asm-offsets.h> |
17 | #include <asm/unistd.h> | 17 | #include <asm/unistd.h> |
18 | 18 | ||
19 | /* Offset for the low 32-bit part of a field of long type */ | ||
20 | #ifdef CONFIG_PPC64 | ||
21 | #define LOPART 4 | ||
22 | #else | ||
23 | #define LOPART 0 | ||
24 | #endif | ||
25 | |||
19 | .text | 26 | .text |
20 | /* | 27 | /* |
21 | * Exact prototype of gettimeofday | 28 | * Exact prototype of gettimeofday |
@@ -90,101 +97,53 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) | |||
90 | 97 | ||
91 | mflr r12 /* r12 saves lr */ | 98 | mflr r12 /* r12 saves lr */ |
92 | .cfi_register lr,r12 | 99 | .cfi_register lr,r12 |
93 | mr r10,r3 /* r10 saves id */ | ||
94 | mr r11,r4 /* r11 saves tp */ | 100 | mr r11,r4 /* r11 saves tp */ |
95 | bl __get_datapage@local /* get data page */ | 101 | bl __get_datapage@local /* get data page */ |
96 | mr r9,r3 /* datapage ptr in r9 */ | 102 | 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 | 103 | ||
111 | /* get remaining xsec and convert to nsec. we scale | 104 | 50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */ |
112 | * up remaining xsec by 12 bits and get the top 32 bits | 105 | bne cr1,80f /* not monotonic -> all done */ |
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 | 106 | ||
126 | /* | 107 | /* |
127 | * CLOCK_MONOTONIC | 108 | * CLOCK_MONOTONIC |
128 | */ | 109 | */ |
129 | 110 | ||
130 | 50: 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 | 111 | /* now we must fixup using wall to monotonic. We need to snapshot |
148 | * that value and do the counter trick again. Fortunately, we still | 112 | * 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. | 113 | * 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 | 114 | * At this point, r3,r4 contain our sec/nsec values, r5 and r6 |
151 | * can be used | 115 | * can be used, r7 contains NSEC_PER_SEC. |
152 | */ | 116 | */ |
153 | 117 | ||
154 | lwz r3,WTOM_CLOCK_SEC(r9) | 118 | lwz r5,WTOM_CLOCK_SEC(r9) |
155 | lwz r4,WTOM_CLOCK_NSEC(r9) | 119 | lwz r6,WTOM_CLOCK_NSEC(r9) |
156 | 120 | ||
157 | /* We now have our result in r3,r4. We create a fake dependency | 121 | /* We now have our offset in r5,r6. We create a fake dependency |
158 | * on that result and re-check the counter | 122 | * on that value and re-check the counter |
159 | */ | 123 | */ |
160 | or r5,r4,r3 | 124 | or r0,r6,r5 |
161 | xor r0,r5,r5 | 125 | xor r0,r0,r0 |
162 | add r9,r9,r0 | 126 | add r9,r9,r0 |
163 | #ifdef CONFIG_PPC64 | 127 | lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) |
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 */ | 128 | cmpl cr0,r8,r0 /* check if updated */ |
169 | bne- 50b | 129 | bne- 50b |
170 | 130 | ||
171 | /* Calculate and store result. Note that this mimmics the C code, | 131 | /* Calculate and store result. Note that this mimics the C code, |
172 | * which may cause funny results if nsec goes negative... is that | 132 | * which may cause funny results if nsec goes negative... is that |
173 | * possible at all ? | 133 | * possible at all ? |
174 | */ | 134 | */ |
175 | add r3,r3,r6 | 135 | add r3,r3,r5 |
176 | add r4,r4,r7 | 136 | add r4,r4,r6 |
177 | lis r5,NSEC_PER_SEC@h | 137 | cmpw cr0,r4,r7 |
178 | ori r5,r5,NSEC_PER_SEC@l | 138 | cmpwi cr1,r4,0 |
179 | cmpl cr0,r4,r5 | ||
180 | cmpli cr1,r4,0 | ||
181 | blt 1f | 139 | blt 1f |
182 | subf r4,r5,r4 | 140 | subf r4,r7,r4 |
183 | addi r3,r3,1 | 141 | addi r3,r3,1 |
184 | 1: bge cr1,1f | 142 | 1: bge cr1,80f |
185 | addi r3,r3,-1 | 143 | addi r3,r3,-1 |
186 | add r4,r4,r5 | 144 | add r4,r4,r7 |
187 | 1: stw r3,TSPC32_TV_SEC(r11) | 145 | |
146 | 80: stw r3,TSPC32_TV_SEC(r11) | ||
188 | stw r4,TSPC32_TV_NSEC(r11) | 147 | stw r4,TSPC32_TV_NSEC(r11) |
189 | 148 | ||
190 | mtlr r12 | 149 | mtlr r12 |
@@ -195,10 +154,6 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) | |||
195 | /* | 154 | /* |
196 | * syscall fallback | 155 | * syscall fallback |
197 | */ | 156 | */ |
198 | 98: | ||
199 | mtlr r12 | ||
200 | mr r3,r10 | ||
201 | mr r4,r11 | ||
202 | 99: | 157 | 99: |
203 | li r0,__NR_clock_gettime | 158 | li r0,__NR_clock_gettime |
204 | sc | 159 | sc |
@@ -254,11 +209,7 @@ __do_get_xsec: | |||
254 | /* Check for update count & load values. We use the low | 209 | /* Check for update count & load values. We use the low |
255 | * order 32 bits of the update count | 210 | * order 32 bits of the update count |
256 | */ | 211 | */ |
257 | #ifdef CONFIG_PPC64 | 212 | 1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9) |
258 | 1: lwz r8,(CFG_TB_UPDATE_COUNT+4)(r9) | ||
259 | #else | ||
260 | 1: lwz r8,(CFG_TB_UPDATE_COUNT)(r9) | ||
261 | #endif | ||
262 | andi. r0,r8,1 /* pending update ? loop */ | 213 | andi. r0,r8,1 /* pending update ? loop */ |
263 | bne- 1b | 214 | bne- 1b |
264 | xor r0,r8,r8 /* create dependency */ | 215 | xor r0,r8,r8 /* create dependency */ |
@@ -305,11 +256,7 @@ __do_get_xsec: | |||
305 | or r6,r4,r3 | 256 | or r6,r4,r3 |
306 | xor r0,r6,r6 | 257 | xor r0,r6,r6 |
307 | add r9,r9,r0 | 258 | add r9,r9,r0 |
308 | #ifdef CONFIG_PPC64 | 259 | lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) |
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 */ | 260 | cmpl cr0,r8,r0 /* check if updated */ |
314 | bne- 1b | 261 | bne- 1b |
315 | 262 | ||
@@ -322,3 +269,98 @@ __do_get_xsec: | |||
322 | */ | 269 | */ |
323 | 3: blr | 270 | 3: blr |
324 | .cfi_endproc | 271 | .cfi_endproc |
272 | |||
273 | /* | ||
274 | * This is the core of clock_gettime(), it returns the current | ||
275 | * time in seconds and nanoseconds in r3 and r4. | ||
276 | * It expects the datapage ptr in r9 and doesn't clobber it. | ||
277 | * It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7. | ||
278 | * On return, r8 contains the counter value that can be reused. | ||
279 | * This clobbers cr0 but not any other cr field. | ||
280 | */ | ||
281 | __do_get_tspec: | ||
282 | .cfi_startproc | ||
283 | /* Check for update count & load values. We use the low | ||
284 | * order 32 bits of the update count | ||
285 | */ | ||
286 | 1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9) | ||
287 | andi. r0,r8,1 /* pending update ? loop */ | ||
288 | bne- 1b | ||
289 | xor r0,r8,r8 /* create dependency */ | ||
290 | add r9,r9,r0 | ||
291 | |||
292 | /* Load orig stamp (offset to TB) */ | ||
293 | lwz r5,CFG_TB_ORIG_STAMP(r9) | ||
294 | lwz r6,(CFG_TB_ORIG_STAMP+4)(r9) | ||
295 | |||
296 | /* Get a stable TB value */ | ||
297 | 2: mftbu r3 | ||
298 | mftbl r4 | ||
299 | mftbu r0 | ||
300 | cmpl cr0,r3,r0 | ||
301 | bne- 2b | ||
302 | |||
303 | /* Subtract tb orig stamp and shift left 12 bits. | ||
304 | */ | ||
305 | subfc r7,r6,r4 | ||
306 | subfe r0,r5,r3 | ||
307 | slwi r0,r0,12 | ||
308 | rlwimi. r0,r7,12,20,31 | ||
309 | slwi r7,r7,12 | ||
310 | |||
311 | /* Load scale factor & do multiplication */ | ||
312 | lwz r5,CFG_TB_TO_XS(r9) /* load values */ | ||
313 | lwz r6,(CFG_TB_TO_XS+4)(r9) | ||
314 | mulhwu r3,r7,r6 | ||
315 | mullw r10,r7,r5 | ||
316 | mulhwu r4,r7,r5 | ||
317 | addc r10,r3,r10 | ||
318 | li r3,0 | ||
319 | |||
320 | beq+ 4f /* skip high part computation if 0 */ | ||
321 | mulhwu r3,r0,r5 | ||
322 | mullw r7,r0,r5 | ||
323 | mulhwu r5,r0,r6 | ||
324 | mullw r6,r0,r6 | ||
325 | adde r4,r4,r7 | ||
326 | addze r3,r3 | ||
327 | addc r4,r4,r5 | ||
328 | addze r3,r3 | ||
329 | addc r10,r10,r6 | ||
330 | |||
331 | 4: addze r4,r4 /* add in carry */ | ||
332 | lis r7,NSEC_PER_SEC@h | ||
333 | ori r7,r7,NSEC_PER_SEC@l | ||
334 | mulhwu r4,r4,r7 /* convert to nanoseconds */ | ||
335 | |||
336 | /* At this point, we have seconds & nanoseconds since the xtime | ||
337 | * stamp in r3+CA and r4. Load & add the xtime stamp. | ||
338 | */ | ||
339 | #ifdef CONFIG_PPC64 | ||
340 | lwz r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9) | ||
341 | lwz r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9) | ||
342 | #else | ||
343 | lwz r5,STAMP_XTIME+TSPC32_TV_SEC(r9) | ||
344 | lwz r6,STAMP_XTIME+TSPC32_TV_NSEC(r9) | ||
345 | #endif | ||
346 | add r4,r4,r6 | ||
347 | adde r3,r3,r5 | ||
348 | |||
349 | /* We now have our result in r3,r4. We create a fake dependency | ||
350 | * on that result and re-check the counter | ||
351 | */ | ||
352 | or r6,r4,r3 | ||
353 | xor r0,r6,r6 | ||
354 | add r9,r9,r0 | ||
355 | lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) | ||
356 | cmpl cr0,r8,r0 /* check if updated */ | ||
357 | bne- 1b | ||
358 | |||
359 | /* check for nanosecond overflow and adjust if necessary */ | ||
360 | cmpw r4,r7 | ||
361 | bltlr /* all done if no overflow */ | ||
362 | subf r4,r7,r4 /* adjust if overflow */ | ||
363 | addi r3,r3,1 | ||
364 | |||
365 | blr | ||
366 | .cfi_endproc | ||