| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Userland implementation of gettimeofday() for 32 bits processes in a |
|---|
| 3 | 4 | * ppc64 kernel for use in the vDSO |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org, |
|---|
| 6 | 7 | * 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 | 8 | */ |
|---|
| 13 | 9 | #include <asm/processor.h> |
|---|
| 14 | 10 | #include <asm/ppc_asm.h> |
|---|
| 15 | 11 | #include <asm/vdso.h> |
|---|
| 12 | +#include <asm/vdso_datapage.h> |
|---|
| 16 | 13 | #include <asm/asm-offsets.h> |
|---|
| 17 | 14 | #include <asm/unistd.h> |
|---|
| 18 | 15 | |
|---|
| 19 | 16 | /* Offset for the low 32-bit part of a field of long type */ |
|---|
| 20 | 17 | #ifdef CONFIG_PPC64 |
|---|
| 21 | 18 | #define LOPART 4 |
|---|
| 22 | | -#define TSPEC_TV_SEC TSPC64_TV_SEC+LOPART |
|---|
| 23 | 19 | #else |
|---|
| 24 | 20 | #define LOPART 0 |
|---|
| 25 | | -#define TSPEC_TV_SEC TSPC32_TV_SEC |
|---|
| 26 | 21 | #endif |
|---|
| 27 | 22 | |
|---|
| 28 | 23 | .text |
|---|
| .. | .. |
|---|
| 37 | 32 | mflr r12 |
|---|
| 38 | 33 | .cfi_register lr,r12 |
|---|
| 39 | 34 | |
|---|
| 40 | | - mr r10,r3 /* r10 saves tv */ |
|---|
| 35 | + mr. r10,r3 /* r10 saves tv */ |
|---|
| 41 | 36 | mr r11,r4 /* r11 saves tz */ |
|---|
| 42 | | - bl __get_datapage@local /* get data page */ |
|---|
| 43 | | - mr r9, r3 /* datapage ptr in r9 */ |
|---|
| 44 | | - cmplwi r10,0 /* check if tv is NULL */ |
|---|
| 37 | + get_datapage r9, r0 |
|---|
| 45 | 38 | beq 3f |
|---|
| 46 | | - lis r7,1000000@ha /* load up USEC_PER_SEC */ |
|---|
| 47 | | - addi r7,r7,1000000@l /* so we get microseconds in r4 */ |
|---|
| 39 | + LOAD_REG_IMMEDIATE(r7, 1000000) /* load up USEC_PER_SEC */ |
|---|
| 48 | 40 | bl __do_get_tspec@local /* get sec/usec from tb & kernel */ |
|---|
| 49 | 41 | stw r3,TVAL32_TV_SEC(r10) |
|---|
| 50 | 42 | stw r4,TVAL32_TV_USEC(r10) |
|---|
| 51 | 43 | |
|---|
| 52 | 44 | 3: cmplwi r11,0 /* check if tz is NULL */ |
|---|
| 53 | | - beq 1f |
|---|
| 45 | + mtlr r12 |
|---|
| 46 | + crclr cr0*4+so |
|---|
| 47 | + li r3,0 |
|---|
| 48 | + beqlr |
|---|
| 49 | + |
|---|
| 54 | 50 | lwz r4,CFG_TZ_MINUTEWEST(r9)/* fill tz */ |
|---|
| 55 | 51 | lwz r5,CFG_TZ_DSTTIME(r9) |
|---|
| 56 | 52 | stw r4,TZONE_TZ_MINWEST(r11) |
|---|
| 57 | 53 | stw r5,TZONE_TZ_DSTTIME(r11) |
|---|
| 58 | 54 | |
|---|
| 59 | | -1: mtlr r12 |
|---|
| 60 | | - crclr cr0*4+so |
|---|
| 61 | | - li r3,0 |
|---|
| 62 | 55 | blr |
|---|
| 63 | 56 | .cfi_endproc |
|---|
| 64 | 57 | V_FUNCTION_END(__kernel_gettimeofday) |
|---|
| .. | .. |
|---|
| 75 | 68 | cmpli cr0,r3,CLOCK_REALTIME |
|---|
| 76 | 69 | cmpli cr1,r3,CLOCK_MONOTONIC |
|---|
| 77 | 70 | cror cr0*4+eq,cr0*4+eq,cr1*4+eq |
|---|
| 78 | | - bne cr0,99f |
|---|
| 71 | + |
|---|
| 72 | + cmpli cr5,r3,CLOCK_REALTIME_COARSE |
|---|
| 73 | + cmpli cr6,r3,CLOCK_MONOTONIC_COARSE |
|---|
| 74 | + cror cr5*4+eq,cr5*4+eq,cr6*4+eq |
|---|
| 75 | + |
|---|
| 76 | + cror cr0*4+eq,cr0*4+eq,cr5*4+eq |
|---|
| 77 | + bne cr0, .Lgettime_fallback |
|---|
| 79 | 78 | |
|---|
| 80 | 79 | mflr r12 /* r12 saves lr */ |
|---|
| 81 | 80 | .cfi_register lr,r12 |
|---|
| 82 | 81 | mr r11,r4 /* r11 saves tp */ |
|---|
| 83 | | - bl __get_datapage@local /* get data page */ |
|---|
| 84 | | - mr r9,r3 /* datapage ptr in r9 */ |
|---|
| 85 | | - lis r7,NSEC_PER_SEC@h /* want nanoseconds */ |
|---|
| 86 | | - ori r7,r7,NSEC_PER_SEC@l |
|---|
| 87 | | -50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */ |
|---|
| 88 | | - bne cr1,80f /* not monotonic -> all done */ |
|---|
| 82 | + get_datapage r9, r0 |
|---|
| 83 | + LOAD_REG_IMMEDIATE(r7, NSEC_PER_SEC) /* load up NSEC_PER_SEC */ |
|---|
| 84 | + beq cr5, .Lcoarse_clocks |
|---|
| 85 | +.Lprecise_clocks: |
|---|
| 86 | + bl __do_get_tspec@local /* get sec/nsec from tb & kernel */ |
|---|
| 87 | + bne cr1, .Lfinish /* not monotonic -> all done */ |
|---|
| 89 | 88 | |
|---|
| 90 | 89 | /* |
|---|
| 91 | 90 | * CLOCK_MONOTONIC |
|---|
| .. | .. |
|---|
| 109 | 108 | add r9,r9,r0 |
|---|
| 110 | 109 | lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) |
|---|
| 111 | 110 | cmpl cr0,r8,r0 /* check if updated */ |
|---|
| 112 | | - bne- 50b |
|---|
| 111 | + bne- .Lprecise_clocks |
|---|
| 112 | + b .Lfinish_monotonic |
|---|
| 113 | + |
|---|
| 114 | + /* |
|---|
| 115 | + * For coarse clocks we get data directly from the vdso data page, so |
|---|
| 116 | + * we don't need to call __do_get_tspec, but we still need to do the |
|---|
| 117 | + * counter trick. |
|---|
| 118 | + */ |
|---|
| 119 | +.Lcoarse_clocks: |
|---|
| 120 | + lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9) |
|---|
| 121 | + andi. r0,r8,1 /* pending update ? loop */ |
|---|
| 122 | + bne- .Lcoarse_clocks |
|---|
| 123 | + add r9,r9,r0 /* r0 is already 0 */ |
|---|
| 124 | + |
|---|
| 125 | + /* |
|---|
| 126 | + * CLOCK_REALTIME_COARSE, below values are needed for MONOTONIC_COARSE |
|---|
| 127 | + * too |
|---|
| 128 | + */ |
|---|
| 129 | + lwz r3,STAMP_XTIME_SEC+LOPART(r9) |
|---|
| 130 | + lwz r4,STAMP_XTIME_NSEC+LOPART(r9) |
|---|
| 131 | + bne cr6,1f |
|---|
| 132 | + |
|---|
| 133 | + /* CLOCK_MONOTONIC_COARSE */ |
|---|
| 134 | + lwz r5,(WTOM_CLOCK_SEC+LOPART)(r9) |
|---|
| 135 | + lwz r6,WTOM_CLOCK_NSEC(r9) |
|---|
| 136 | + |
|---|
| 137 | + /* check if counter has updated */ |
|---|
| 138 | + or r0,r6,r5 |
|---|
| 139 | +1: or r0,r0,r3 |
|---|
| 140 | + or r0,r0,r4 |
|---|
| 141 | + xor r0,r0,r0 |
|---|
| 142 | + add r3,r3,r0 |
|---|
| 143 | + lwz r0,CFG_TB_UPDATE_COUNT+LOPART(r9) |
|---|
| 144 | + cmpl cr0,r0,r8 /* check if updated */ |
|---|
| 145 | + bne- .Lcoarse_clocks |
|---|
| 146 | + |
|---|
| 147 | + /* Counter has not updated, so continue calculating proper values for |
|---|
| 148 | + * sec and nsec if monotonic coarse, or just return with the proper |
|---|
| 149 | + * values for realtime. |
|---|
| 150 | + */ |
|---|
| 151 | + bne cr6, .Lfinish |
|---|
| 113 | 152 | |
|---|
| 114 | 153 | /* Calculate and store result. Note that this mimics the C code, |
|---|
| 115 | 154 | * which may cause funny results if nsec goes negative... is that |
|---|
| 116 | 155 | * possible at all ? |
|---|
| 117 | 156 | */ |
|---|
| 157 | +.Lfinish_monotonic: |
|---|
| 118 | 158 | add r3,r3,r5 |
|---|
| 119 | 159 | add r4,r4,r6 |
|---|
| 120 | 160 | cmpw cr0,r4,r7 |
|---|
| .. | .. |
|---|
| 122 | 162 | blt 1f |
|---|
| 123 | 163 | subf r4,r7,r4 |
|---|
| 124 | 164 | addi r3,r3,1 |
|---|
| 125 | | -1: bge cr1,80f |
|---|
| 165 | +1: bge cr1, .Lfinish |
|---|
| 126 | 166 | addi r3,r3,-1 |
|---|
| 127 | 167 | add r4,r4,r7 |
|---|
| 128 | 168 | |
|---|
| 129 | | -80: stw r3,TSPC32_TV_SEC(r11) |
|---|
| 169 | +.Lfinish: |
|---|
| 170 | + stw r3,TSPC32_TV_SEC(r11) |
|---|
| 130 | 171 | stw r4,TSPC32_TV_NSEC(r11) |
|---|
| 131 | 172 | |
|---|
| 132 | 173 | mtlr r12 |
|---|
| .. | .. |
|---|
| 137 | 178 | /* |
|---|
| 138 | 179 | * syscall fallback |
|---|
| 139 | 180 | */ |
|---|
| 140 | | -99: |
|---|
| 181 | +.Lgettime_fallback: |
|---|
| 141 | 182 | li r0,__NR_clock_gettime |
|---|
| 142 | 183 | .cfi_restore lr |
|---|
| 143 | 184 | sc |
|---|
| .. | .. |
|---|
| 155 | 196 | V_FUNCTION_BEGIN(__kernel_clock_getres) |
|---|
| 156 | 197 | .cfi_startproc |
|---|
| 157 | 198 | /* Check for supported clock IDs */ |
|---|
| 158 | | - cmpwi cr0,r3,CLOCK_REALTIME |
|---|
| 159 | | - cmpwi cr1,r3,CLOCK_MONOTONIC |
|---|
| 160 | | - cror cr0*4+eq,cr0*4+eq,cr1*4+eq |
|---|
| 161 | | - bne cr0,99f |
|---|
| 199 | + cmplwi cr0, r3, CLOCK_MAX |
|---|
| 200 | + cmpwi cr1, r3, CLOCK_REALTIME_COARSE |
|---|
| 201 | + cmpwi cr7, r3, CLOCK_MONOTONIC_COARSE |
|---|
| 202 | + bgt cr0, 99f |
|---|
| 203 | + LOAD_REG_IMMEDIATE(r5, KTIME_LOW_RES) |
|---|
| 204 | + beq cr1, 1f |
|---|
| 205 | + beq cr7, 1f |
|---|
| 162 | 206 | |
|---|
| 163 | 207 | mflr r12 |
|---|
| 164 | 208 | .cfi_register lr,r12 |
|---|
| 165 | | - bl __get_datapage@local /* get data page */ |
|---|
| 209 | + get_datapage r3, r0 |
|---|
| 166 | 210 | lwz r5, CLOCK_HRTIMER_RES(r3) |
|---|
| 167 | 211 | mtlr r12 |
|---|
| 168 | | - li r3,0 |
|---|
| 212 | +1: li r3,0 |
|---|
| 169 | 213 | cmpli cr0,r4,0 |
|---|
| 170 | 214 | crclr cr0*4+so |
|---|
| 171 | 215 | beqlr |
|---|
| .. | .. |
|---|
| 196 | 240 | .cfi_register lr,r12 |
|---|
| 197 | 241 | |
|---|
| 198 | 242 | mr r11,r3 /* r11 holds t */ |
|---|
| 199 | | - bl __get_datapage@local |
|---|
| 200 | | - mr r9, r3 /* datapage ptr in r9 */ |
|---|
| 243 | + get_datapage r9, r0 |
|---|
| 201 | 244 | |
|---|
| 202 | | - lwz r3,STAMP_XTIME+TSPEC_TV_SEC(r9) |
|---|
| 245 | + lwz r3,STAMP_XTIME_SEC+LOPART(r9) |
|---|
| 203 | 246 | |
|---|
| 204 | 247 | cmplwi r11,0 /* check if t is NULL */ |
|---|
| 205 | | - beq 2f |
|---|
| 206 | | - stw r3,0(r11) /* store result at *t */ |
|---|
| 207 | | -2: mtlr r12 |
|---|
| 248 | + mtlr r12 |
|---|
| 208 | 249 | crclr cr0*4+so |
|---|
| 250 | + beqlr |
|---|
| 251 | + stw r3,0(r11) /* store result at *t */ |
|---|
| 209 | 252 | blr |
|---|
| 210 | 253 | .cfi_endproc |
|---|
| 211 | 254 | V_FUNCTION_END(__kernel_time) |
|---|
| .. | .. |
|---|
| 275 | 318 | * as a 32.32 fixed-point number in r3 and r4. |
|---|
| 276 | 319 | * Load & add the xtime stamp. |
|---|
| 277 | 320 | */ |
|---|
| 278 | | - lwz r5,STAMP_XTIME+TSPEC_TV_SEC(r9) |
|---|
| 321 | + lwz r5,STAMP_XTIME_SEC+LOPART(r9) |
|---|
| 279 | 322 | lwz r6,STAMP_SEC_FRAC(r9) |
|---|
| 280 | 323 | addc r4,r4,r6 |
|---|
| 281 | 324 | adde r3,r3,r5 |
|---|