tile: implement gettimeofday() via vDSO
[deliverable/linux.git] / arch / tile / kernel / vdso / vgettimeofday.c
1 /*
2 * Copyright 2012 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 */
14
15 #define VDSO_BUILD /* avoid some shift warnings for -m32 in <asm/page.h> */
16 #include <linux/time.h>
17 #include <asm/timex.h>
18 #include <asm/vdso.h>
19
20 #if CHIP_HAS_SPLIT_CYCLE()
21 static inline cycles_t get_cycles_inline(void)
22 {
23 unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH);
24 unsigned int low = __insn_mfspr(SPR_CYCLE_LOW);
25 unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH);
26
27 while (unlikely(high != high2)) {
28 low = __insn_mfspr(SPR_CYCLE_LOW);
29 high = high2;
30 high2 = __insn_mfspr(SPR_CYCLE_HIGH);
31 }
32
33 return (((cycles_t)high) << 32) | low;
34 }
35 #define get_cycles get_cycles_inline
36 #endif
37
38 /*
39 * Find out the vDSO data page address in the process address space.
40 */
41 inline unsigned long get_datapage(void)
42 {
43 unsigned long ret;
44
45 /* vdso data page located in the 2nd vDSO page. */
46 asm volatile ("lnk %0" : "=r"(ret));
47 ret &= ~(PAGE_SIZE - 1);
48 ret += PAGE_SIZE;
49
50 return ret;
51 }
52
53 int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
54 {
55 cycles_t cycles;
56 unsigned long count, sec, ns;
57 volatile struct vdso_data *vdso_data;
58
59 vdso_data = (struct vdso_data *)get_datapage();
60 /* The use of the timezone is obsolete, normally tz is NULL. */
61 if (unlikely(tz != NULL)) {
62 while (1) {
63 /* Spin until the update finish. */
64 count = vdso_data->tz_update_count;
65 if (count & 1)
66 continue;
67
68 tz->tz_minuteswest = vdso_data->tz_minuteswest;
69 tz->tz_dsttime = vdso_data->tz_dsttime;
70
71 /* Check whether updated, read again if so. */
72 if (count == vdso_data->tz_update_count)
73 break;
74 }
75 }
76
77 if (unlikely(tv == NULL))
78 return 0;
79
80 while (1) {
81 /* Spin until the update finish. */
82 count = vdso_data->tb_update_count;
83 if (count & 1)
84 continue;
85
86 cycles = (get_cycles() - vdso_data->xtime_tod_stamp);
87 ns = (cycles * vdso_data->mult) >> vdso_data->shift;
88 sec = vdso_data->xtime_clock_sec;
89 ns += vdso_data->xtime_clock_nsec;
90 if (ns >= NSEC_PER_SEC) {
91 ns -= NSEC_PER_SEC;
92 sec += 1;
93 }
94
95 /* Check whether updated, read again if so. */
96 if (count == vdso_data->tb_update_count)
97 break;
98 }
99
100 tv->tv_sec = sec;
101 tv->tv_usec = ns / 1000;
102
103 return 0;
104 }
105
106 int gettimeofday(struct timeval *tv, struct timezone *tz)
107 __attribute__((weak, alias("__vdso_gettimeofday")));
This page took 0.050821 seconds and 5 git commands to generate.