Merge /spare/repo/linux-2.6/
[sfrench/cifs-2.6.git] / arch / ppc64 / kernel / vdso32 / gettimeofday.S
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/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  */
26 V_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         bl      __do_get_xsec@local     /* get xsec from tb & kernel */
36         bne-    2f                      /* out of line -> do syscall */
37
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)
42
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)
52
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)
59
60 1:      mtlr    r12
61         li      r3,0
62         blr
63
64 2:      mr      r3,r10
65         mr      r4,r11
66         li      r0,__NR_gettimeofday
67         sc
68         b       1b
69   .cfi_endproc
70 V_FUNCTION_END(__kernel_gettimeofday)
71
72 /*
73  * This is the core of gettimeofday(), it returns the xsec
74  * value in r3 & r4 and expects the datapage ptr (non clobbered)
75  * in r9. clobbers r0,r4,r5,r6,r7,r8
76 */
77 __do_get_xsec:
78   .cfi_startproc
79         /* Check for update count & load values. We use the low
80          * order 32 bits of the update count
81          */
82 1:      lwz     r8,(CFG_TB_UPDATE_COUNT+4)(r9)
83         andi.   r0,r8,1                 /* pending update ? loop */
84         bne-    1b
85         xor     r0,r8,r8                /* create dependency */
86         add     r9,r9,r0
87
88         /* Load orig stamp (offset to TB) */
89         lwz     r5,CFG_TB_ORIG_STAMP(r9)
90         lwz     r6,(CFG_TB_ORIG_STAMP+4)(r9)
91
92         /* Get a stable TB value */
93 2:      mftbu   r3
94         mftbl   r4
95         mftbu   r0
96         cmpl    cr0,r3,r0
97         bne-    2b
98
99         /* Substract tb orig stamp. If the high part is non-zero, we jump to the
100          * slow path which call the syscall. If it's ok, then we have our 32 bits
101          * tb_ticks value in r7
102          */
103         subfc   r7,r6,r4
104         subfe.  r0,r5,r3
105         bne-    3f
106
107         /* Load scale factor & do multiplication */
108         lwz     r5,CFG_TB_TO_XS(r9)     /* load values */
109         lwz     r6,(CFG_TB_TO_XS+4)(r9)
110         mulhwu  r4,r7,r5
111         mulhwu  r6,r7,r6
112         mullw   r6,r7,r5
113         addc    r6,r6,r0
114
115         /* At this point, we have the scaled xsec value in r4 + XER:CA
116          * we load & add the stamp since epoch
117          */
118         lwz     r5,CFG_STAMP_XSEC(r9)
119         lwz     r6,(CFG_STAMP_XSEC+4)(r9)
120         adde    r4,r4,r6
121         addze   r3,r5
122
123         /* We now have our result in r3,r4. We create a fake dependency
124          * on that result and re-check the counter
125          */
126         xor     r0,r4,r4
127         add     r9,r9,r0
128         lwz     r0,(CFG_TB_UPDATE_COUNT+4)(r9)
129         cmpl    cr0,r8,r0               /* check if updated */
130         bne-    1b
131
132         /* Warning ! The caller expects CR:EQ to be set to indicate a
133          * successful calculation (so it won't fallback to the syscall
134          * method). We have overriden that CR bit in the counter check,
135          * but fortunately, the loop exit condition _is_ CR:EQ set, so
136          * we can exit safely here. If you change this code, be careful
137          * of that side effect.
138          */
139 3:      blr
140   .cfi_endproc