~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to arch/x86/vdso/vclock_gettime.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * Copyright 2006 Andi Kleen, SUSE Labs.
3
3
 * Subject to the GNU Public License, v.2
4
4
 *
5
 
 * Fast user context implementation of clock_gettime and gettimeofday.
 
5
 * Fast user context implementation of clock_gettime, gettimeofday, and time.
6
6
 *
7
7
 * The code should have no internal unresolved relocations.
8
8
 * Check with readelf after changing.
22
22
#include <asm/hpet.h>
23
23
#include <asm/unistd.h>
24
24
#include <asm/io.h>
25
 
#include <asm/trace-clock.h>
26
 
#include <asm/timer.h>
27
 
#include "vextern.h"
28
25
 
29
 
#define gtod vdso_vsyscall_gtod_data
 
26
#define gtod (&VVAR(vsyscall_gtod_data))
30
27
 
31
28
notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
32
29
{
58
55
        return 0;
59
56
}
60
57
 
61
 
/* Copy of the version in kernel/time.c which we cannot directly access */
62
 
notrace static void
63
 
vset_normalized_timespec(struct timespec *ts, long sec, long nsec)
64
 
{
65
 
        while (nsec >= NSEC_PER_SEC) {
66
 
                nsec -= NSEC_PER_SEC;
67
 
                ++sec;
68
 
        }
69
 
        while (nsec < 0) {
70
 
                nsec += NSEC_PER_SEC;
71
 
                --sec;
72
 
        }
73
 
        ts->tv_sec = sec;
74
 
        ts->tv_nsec = nsec;
75
 
}
76
 
 
77
58
notrace static noinline int do_monotonic(struct timespec *ts)
78
59
{
79
60
        unsigned long seq, ns, secs;
84
65
                secs += gtod->wall_to_monotonic.tv_sec;
85
66
                ns += gtod->wall_to_monotonic.tv_nsec;
86
67
        } while (unlikely(read_seqretry(&gtod->lock, seq)));
87
 
        vset_normalized_timespec(ts, secs, ns);
 
68
 
 
69
        /* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec
 
70
         * are all guaranteed to be nonnegative.
 
71
         */
 
72
        while (ns >= NSEC_PER_SEC) {
 
73
                ns -= NSEC_PER_SEC;
 
74
                ++secs;
 
75
        }
 
76
        ts->tv_sec = secs;
 
77
        ts->tv_nsec = ns;
 
78
 
88
79
        return 0;
89
80
}
90
81
 
109
100
                secs += gtod->wall_to_monotonic.tv_sec;
110
101
                ns += gtod->wall_to_monotonic.tv_nsec;
111
102
        } while (unlikely(read_seqretry(&gtod->lock, seq)));
112
 
        vset_normalized_timespec(ts, secs, ns);
113
 
        return 0;
114
 
}
115
 
 
116
 
/*
117
 
 * If the TSC is synchronized across all CPUs, read the current TSC
118
 
 * and export its value in the nsec field of the timespec
119
 
 */
120
 
notrace static noinline int do_trace_clock(struct timespec *ts)
121
 
{
122
 
        unsigned long seq;
123
 
        union lttng_timespec *lts = (union lttng_timespec *) ts;
124
 
 
125
 
        do {
126
 
                seq = read_seqbegin(&gtod->lock);
127
 
                if (unlikely(!gtod->trace_clock_is_sync))
128
 
                        return vdso_fallback_gettime(CLOCK_TRACE, ts);
129
 
                /*
130
 
                 * We don't protect the rdtsc with the rdtsc_barrier because
131
 
                 * we can't obtain with tracing that level of precision.
132
 
                 * The operation of recording an event is not atomic therefore
133
 
                 * the small chance of imprecision doesn't justify the overhead
134
 
                 * of a barrier.
135
 
                 */
136
 
                /*
137
 
                 * TODO: check that vget_cycles(), using paravirt ops, will
138
 
                 * match the TSC read by get_cycles() at the kernel level.
139
 
                 */
140
 
                lts->lttng_ts = vget_cycles();
141
 
        } while (unlikely(read_seqretry(&gtod->lock, seq)));
142
 
 
143
 
        return 0;
144
 
}
145
 
 
146
 
/*
147
 
 * Returns the cpu_khz, it needs to be a syscall because we can't access
148
 
 * this value from userspace and it will only be called at the beginning
149
 
 * of the tracing session
150
 
 */
151
 
notrace static noinline int do_trace_clock_freq(struct timespec *ts)
152
 
{
153
 
        return vdso_fallback_gettime(CLOCK_TRACE_FREQ, ts);
 
103
 
 
104
        /* wall_time_nsec and wall_to_monotonic.tv_nsec are
 
105
         * guaranteed to be between 0 and NSEC_PER_SEC.
 
106
         */
 
107
        if (ns >= NSEC_PER_SEC) {
 
108
                ns -= NSEC_PER_SEC;
 
109
                ++secs;
 
110
        }
 
111
        ts->tv_sec = secs;
 
112
        ts->tv_nsec = ns;
 
113
 
 
114
        return 0;
154
115
}
155
116
 
156
117
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
169
130
                        return do_realtime_coarse(ts);
170
131
                case CLOCK_MONOTONIC_COARSE:
171
132
                        return do_monotonic_coarse(ts);
172
 
                case CLOCK_TRACE:
173
 
                        return do_trace_clock(ts);
174
 
                case CLOCK_TRACE_FREQ:
175
 
                        return do_trace_clock_freq(ts);
176
 
                default:
177
 
                        return -EINVAL;
178
133
                }
179
134
        return vdso_fallback_gettime(clock, ts);
180
135
}
205
160
}
206
161
int gettimeofday(struct timeval *, struct timezone *)
207
162
        __attribute__((weak, alias("__vdso_gettimeofday")));
 
163
 
 
164
/* This will break when the xtime seconds get inaccurate, but that is
 
165
 * unlikely */
 
166
 
 
167
static __always_inline long time_syscall(long *t)
 
168
{
 
169
        long secs;
 
170
        asm volatile("syscall"
 
171
                     : "=a" (secs)
 
172
                     : "0" (__NR_time), "D" (t) : "cc", "r11", "cx", "memory");
 
173
        return secs;
 
174
}
 
175
 
 
176
notrace time_t __vdso_time(time_t *t)
 
177
{
 
178
        time_t result;
 
179
 
 
180
        if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled))
 
181
                return time_syscall(t);
 
182
 
 
183
        /* This is atomic on x86_64 so we don't need any locks. */
 
184
        result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec);
 
185
 
 
186
        if (t)
 
187
                *t = result;
 
188
        return result;
 
189
}
 
190
int time(time_t *t)
 
191
        __attribute__((weak, alias("__vdso_time")));