time: move the timecounter/cyclecounter code into its own file.
[cascardo/linux.git] / kernel / time / timecounter.c
1 /*
2  * linux/kernel/time/timecounter.c
3  *
4  * based on code that migrated away from
5  * linux/kernel/time/clocksource.c
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <linux/export.h>
19 #include <linux/timecounter.h>
20
21 void timecounter_init(struct timecounter *tc,
22                       const struct cyclecounter *cc,
23                       u64 start_tstamp)
24 {
25         tc->cc = cc;
26         tc->cycle_last = cc->read(cc);
27         tc->nsec = start_tstamp;
28 }
29 EXPORT_SYMBOL_GPL(timecounter_init);
30
31 /**
32  * timecounter_read_delta - get nanoseconds since last call of this function
33  * @tc:         Pointer to time counter
34  *
35  * When the underlying cycle counter runs over, this will be handled
36  * correctly as long as it does not run over more than once between
37  * calls.
38  *
39  * The first call to this function for a new time counter initializes
40  * the time tracking and returns an undefined result.
41  */
42 static u64 timecounter_read_delta(struct timecounter *tc)
43 {
44         cycle_t cycle_now, cycle_delta;
45         u64 ns_offset;
46
47         /* read cycle counter: */
48         cycle_now = tc->cc->read(tc->cc);
49
50         /* calculate the delta since the last timecounter_read_delta(): */
51         cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
52
53         /* convert to nanoseconds: */
54         ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta);
55
56         /* update time stamp of timecounter_read_delta() call: */
57         tc->cycle_last = cycle_now;
58
59         return ns_offset;
60 }
61
62 u64 timecounter_read(struct timecounter *tc)
63 {
64         u64 nsec;
65
66         /* increment time by nanoseconds since last call */
67         nsec = timecounter_read_delta(tc);
68         nsec += tc->nsec;
69         tc->nsec = nsec;
70
71         return nsec;
72 }
73 EXPORT_SYMBOL_GPL(timecounter_read);
74
75 u64 timecounter_cyc2time(struct timecounter *tc,
76                          cycle_t cycle_tstamp)
77 {
78         u64 cycle_delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask;
79         u64 nsec;
80
81         /*
82          * Instead of always treating cycle_tstamp as more recent
83          * than tc->cycle_last, detect when it is too far in the
84          * future and treat it as old time stamp instead.
85          */
86         if (cycle_delta > tc->cc->mask / 2) {
87                 cycle_delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask;
88                 nsec = tc->nsec - cyclecounter_cyc2ns(tc->cc, cycle_delta);
89         } else {
90                 nsec = cyclecounter_cyc2ns(tc->cc, cycle_delta) + tc->nsec;
91         }
92
93         return nsec;
94 }
95 EXPORT_SYMBOL_GPL(timecounter_cyc2time);