Commit | Line | Data |
---|---|---|
74d23cc7 RC |
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; | |
2eebdde6 RC |
28 | tc->mask = (1ULL << cc->shift) - 1; |
29 | tc->frac = 0; | |
74d23cc7 RC |
30 | } |
31 | EXPORT_SYMBOL_GPL(timecounter_init); | |
32 | ||
33 | /** | |
34 | * timecounter_read_delta - get nanoseconds since last call of this function | |
35 | * @tc: Pointer to time counter | |
36 | * | |
37 | * When the underlying cycle counter runs over, this will be handled | |
38 | * correctly as long as it does not run over more than once between | |
39 | * calls. | |
40 | * | |
41 | * The first call to this function for a new time counter initializes | |
42 | * the time tracking and returns an undefined result. | |
43 | */ | |
44 | static u64 timecounter_read_delta(struct timecounter *tc) | |
45 | { | |
46 | cycle_t cycle_now, cycle_delta; | |
47 | u64 ns_offset; | |
48 | ||
49 | /* read cycle counter: */ | |
50 | cycle_now = tc->cc->read(tc->cc); | |
51 | ||
52 | /* calculate the delta since the last timecounter_read_delta(): */ | |
53 | cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask; | |
54 | ||
55 | /* convert to nanoseconds: */ | |
2eebdde6 RC |
56 | ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta, |
57 | tc->mask, &tc->frac); | |
74d23cc7 RC |
58 | |
59 | /* update time stamp of timecounter_read_delta() call: */ | |
60 | tc->cycle_last = cycle_now; | |
61 | ||
62 | return ns_offset; | |
63 | } | |
64 | ||
65 | u64 timecounter_read(struct timecounter *tc) | |
66 | { | |
67 | u64 nsec; | |
68 | ||
69 | /* increment time by nanoseconds since last call */ | |
70 | nsec = timecounter_read_delta(tc); | |
71 | nsec += tc->nsec; | |
72 | tc->nsec = nsec; | |
73 | ||
74 | return nsec; | |
75 | } | |
76 | EXPORT_SYMBOL_GPL(timecounter_read); | |
77 | ||
2eebdde6 RC |
78 | /* |
79 | * This is like cyclecounter_cyc2ns(), but it is used for computing a | |
80 | * time previous to the time stored in the cycle counter. | |
81 | */ | |
82 | static u64 cc_cyc2ns_backwards(const struct cyclecounter *cc, | |
83 | cycle_t cycles, u64 mask, u64 frac) | |
84 | { | |
85 | u64 ns = (u64) cycles; | |
86 | ||
87 | ns = ((ns * cc->mult) - frac) >> cc->shift; | |
88 | ||
89 | return ns; | |
90 | } | |
91 | ||
74d23cc7 RC |
92 | u64 timecounter_cyc2time(struct timecounter *tc, |
93 | cycle_t cycle_tstamp) | |
94 | { | |
2eebdde6 RC |
95 | u64 delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask; |
96 | u64 nsec = tc->nsec, frac = tc->frac; | |
74d23cc7 RC |
97 | |
98 | /* | |
99 | * Instead of always treating cycle_tstamp as more recent | |
100 | * than tc->cycle_last, detect when it is too far in the | |
101 | * future and treat it as old time stamp instead. | |
102 | */ | |
2eebdde6 RC |
103 | if (delta > tc->cc->mask / 2) { |
104 | delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask; | |
105 | nsec -= cc_cyc2ns_backwards(tc->cc, delta, tc->mask, frac); | |
74d23cc7 | 106 | } else { |
2eebdde6 | 107 | nsec += cyclecounter_cyc2ns(tc->cc, delta, tc->mask, &frac); |
74d23cc7 RC |
108 | } |
109 | ||
110 | return nsec; | |
111 | } | |
112 | EXPORT_SYMBOL_GPL(timecounter_cyc2time); |