2 * linux/kernel/time/timecounter.c
4 * based on code that migrated away from
5 * linux/kernel/time/clocksource.c
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.
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.
18 #include <linux/export.h>
19 #include <linux/timecounter.h>
21 void timecounter_init(struct timecounter
*tc
,
22 const struct cyclecounter
*cc
,
26 tc
->cycle_last
= cc
->read(cc
);
27 tc
->nsec
= start_tstamp
;
28 tc
->mask
= (1ULL << cc
->shift
) - 1;
31 EXPORT_SYMBOL_GPL(timecounter_init
);
34 * timecounter_read_delta - get nanoseconds since last call of this function
35 * @tc: Pointer to time counter
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
41 * The first call to this function for a new time counter initializes
42 * the time tracking and returns an undefined result.
44 static u64
timecounter_read_delta(struct timecounter
*tc
)
46 cycle_t cycle_now
, cycle_delta
;
49 /* read cycle counter: */
50 cycle_now
= tc
->cc
->read(tc
->cc
);
52 /* calculate the delta since the last timecounter_read_delta(): */
53 cycle_delta
= (cycle_now
- tc
->cycle_last
) & tc
->cc
->mask
;
55 /* convert to nanoseconds: */
56 ns_offset
= cyclecounter_cyc2ns(tc
->cc
, cycle_delta
,
59 /* update time stamp of timecounter_read_delta() call: */
60 tc
->cycle_last
= cycle_now
;
65 u64
timecounter_read(struct timecounter
*tc
)
69 /* increment time by nanoseconds since last call */
70 nsec
= timecounter_read_delta(tc
);
76 EXPORT_SYMBOL_GPL(timecounter_read
);
79 * This is like cyclecounter_cyc2ns(), but it is used for computing a
80 * time previous to the time stored in the cycle counter.
82 static u64
cc_cyc2ns_backwards(const struct cyclecounter
*cc
,
83 cycle_t cycles
, u64 mask
, u64 frac
)
85 u64 ns
= (u64
) cycles
;
87 ns
= ((ns
* cc
->mult
) - frac
) >> cc
->shift
;
92 u64
timecounter_cyc2time(struct timecounter
*tc
,
95 u64 delta
= (cycle_tstamp
- tc
->cycle_last
) & tc
->cc
->mask
;
96 u64 nsec
= tc
->nsec
, frac
= tc
->frac
;
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.
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
);
107 nsec
+= cyclecounter_cyc2ns(tc
->cc
, delta
, tc
->mask
, &frac
);
112 EXPORT_SYMBOL_GPL(timecounter_cyc2time
);