blob: c2917b0d96f53a0133946431954111f29a6b8fd2 [file] [log] [blame]
Greg Reide5bf5b22012-10-22 16:05:45 -04001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#include <string.h>
31#include <stdint.h>
32#include <time.h>
33#include <sys/time.h>
34#include <machine/cpu-features.h>
35#include <machine/kernel_user_helper.h>
36
37int clock_gettime(int clk_id, struct timespec *tp)
38{
39 unsigned prelock, postlock;
40
41 /*
42 * Check if the offset in the kernel user helper page has
43 * the flag set appropriately to show that this feature is
44 * enabled in the kernel. If not, default to the original
45 * clock_gettime system call.
46 *
47 * Also, if this is anything other than CLOCK_MONOTONIC, route
48 * to the original system call as well.
49 */
50 if ((__kuser_gtod_feature != __kuser_gtod_feature_flag) ||
51 (clk_id != CLOCK_MONOTONIC))
52 return clock_gettime_syscall(clk_id, tp);
53
54 if (tp) {
55 struct gtod_t dgtod;
56 uint32_t nscount, cycleoffset;
57 uint32_t mono_sec, mono_nsec;
58 uint64_t cycle_delta;
59
60 do {
61 prelock = __kuser_gtod_seqnum;
62
63 dgtod.cycle_last = __kuser_gtod_cycle_last;
64 dgtod.mask = __kuser_gtod_mask;
65 dgtod.mult = __kuser_gtod_mult;
66 dgtod.shift = __kuser_gtod_shift;
67 dgtod.tv_sec = __kuser_gtod_tv_sec;
68 dgtod.tv_nsec = __kuser_gtod_tv_nsec;
69
70 mono_sec = __kuser_gtod_wtm_tv_sec;
71 mono_nsec = __kuser_gtod_wtm_tv_nsec;
72
73 cycleoffset = __kuser_gtod_offset;
74 cycleoffset += __kuser_gtod_cycle_base;
75 nscount = *(uint32_t *)cycleoffset;
76
77 postlock = __kuser_gtod_seqnum;
78 } while (prelock != postlock);
79
80 cycle_delta = (nscount - dgtod.cycle_last) & dgtod.mask;
81 dgtod.tv_nsec += (cycle_delta * dgtod.mult) >> dgtod.shift;
82 dgtod.tv_sec += mono_sec;
83 dgtod.tv_nsec += mono_nsec;
84 while (dgtod.tv_nsec >= NSEC_PER_SEC) {
85 dgtod.tv_sec += 1;
86 dgtod.tv_nsec -= NSEC_PER_SEC;
87 }
88
89 tp->tv_sec = dgtod.tv_sec;
90 tp->tv_nsec = dgtod.tv_nsec;
91 }
92
93 return 0;
94}