Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / ppc64 / kernel / vdso32 / gettimeofday.S
blobca7f415195c4029a4ca2516b71b0cbd107cd088d
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), IBM Corp.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version
10  * 2 of the License, or (at your option) any later version.
11  */
12 #include <linux/config.h>
13 #include <asm/processor.h>
14 #include <asm/ppc_asm.h>
15 #include <asm/vdso.h>
16 #include <asm/offsets.h>
17 #include <asm/unistd.h>
19         .text
21  * Exact prototype of gettimeofday
22  *
23  * int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz);
24  *
25  */
26 V_FUNCTION_BEGIN(__kernel_gettimeofday)
27   .cfi_startproc
28         mflr    r12
29   .cfi_register lr,r12
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         bl      __do_get_xsec@local     /* get xsec from tb & kernel */
36         bne-    2f                      /* out of line -> do syscall */
38         /* seconds are xsec >> 20 */
39         rlwinm  r5,r4,12,20,31
40         rlwimi  r5,r3,12,0,19
41         stw     r5,TVAL32_TV_SEC(r10)
43         /* get remaining xsec and convert to usec. we scale
44          * up remaining xsec by 12 bits and get the top 32 bits
45          * of the multiplication
46          */
47         rlwinm  r5,r4,12,0,19
48         lis     r6,1000000@h
49         ori     r6,r6,1000000@l
50         mulhwu  r5,r5,r6
51         stw     r5,TVAL32_TV_USEC(r10)
53         cmpli   cr0,r11,0               /* check if tz is NULL */
54         beq     1f
55         lwz     r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */
56         lwz     r5,CFG_TZ_DSTTIME(r9)
57         stw     r4,TZONE_TZ_MINWEST(r11)
58         stw     r5,TZONE_TZ_DSTTIME(r11)
60 1:      mtlr    r12
61         blr
63 2:      mr      r3,r10
64         mr      r4,r11
65         li      r0,__NR_gettimeofday
66         sc
67         b       1b
68   .cfi_endproc
69 V_FUNCTION_END(__kernel_gettimeofday)
72  * This is the core of gettimeofday(), it returns the xsec
73  * value in r3 & r4 and expects the datapage ptr (non clobbered)
74  * in r9. clobbers r0,r4,r5,r6,r7,r8
76 __do_get_xsec:
77   .cfi_startproc
78         /* Check for update count & load values. We use the low
79          * order 32 bits of the update count
80          */
81 1:      lwz     r8,(CFG_TB_UPDATE_COUNT+4)(r9)
82         andi.   r0,r8,1                 /* pending update ? loop */
83         bne-    1b
84         xor     r0,r8,r8                /* create dependency */
85         add     r9,r9,r0
87         /* Load orig stamp (offset to TB) */
88         lwz     r5,CFG_TB_ORIG_STAMP(r9)
89         lwz     r6,(CFG_TB_ORIG_STAMP+4)(r9)
91         /* Get a stable TB value */
92 2:      mftbu   r3
93         mftbl   r4
94         mftbu   r0
95         cmpl    cr0,r3,r0
96         bne-    2b
98         /* Substract tb orig stamp. If the high part is non-zero, we jump to the
99          * slow path which call the syscall. If it's ok, then we have our 32 bits
100          * tb_ticks value in r7
101          */
102         subfc   r7,r6,r4
103         subfe.  r0,r5,r3
104         bne-    3f
106         /* Load scale factor & do multiplication */
107         lwz     r5,CFG_TB_TO_XS(r9)     /* load values */
108         lwz     r6,(CFG_TB_TO_XS+4)(r9)
109         mulhwu  r4,r7,r5
110         mulhwu  r6,r7,r6
111         mullw   r6,r7,r5
112         addc    r6,r6,r0
114         /* At this point, we have the scaled xsec value in r4 + XER:CA
115          * we load & add the stamp since epoch
116          */
117         lwz     r5,CFG_STAMP_XSEC(r9)
118         lwz     r6,(CFG_STAMP_XSEC+4)(r9)
119         adde    r4,r4,r6
120         addze   r3,r5
122         /* We now have our result in r3,r4. We create a fake dependency
123          * on that result and re-check the counter
124          */
125         xor     r0,r4,r4
126         add     r9,r9,r0
127         lwz     r0,(CFG_TB_UPDATE_COUNT+4)(r9)
128         cmpl    cr0,r8,r0               /* check if updated */
129         bne-    1b
131         /* Warning ! The caller expects CR:EQ to be set to indicate a
132          * successful calculation (so it won't fallback to the syscall
133          * method). We have overriden that CR bit in the counter check,
134          * but fortunately, the loop exit condition _is_ CR:EQ set, so
135          * we can exit safely here. If you change this code, be careful
136          * of that side effect.
137          */
138 3:      blr
139   .cfi_endproc