^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Based on clocksource code. See commit 74d23cc704d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/timecounter.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) void timecounter_init(struct timecounter *tc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) const struct cyclecounter *cc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) u64 start_tstamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) tc->cc = cc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) tc->cycle_last = cc->read(cc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) tc->nsec = start_tstamp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) tc->mask = (1ULL << cc->shift) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) tc->frac = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) EXPORT_SYMBOL_GPL(timecounter_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * timecounter_read_delta - get nanoseconds since last call of this function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * @tc: Pointer to time counter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * When the underlying cycle counter runs over, this will be handled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * correctly as long as it does not run over more than once between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * calls.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * The first call to this function for a new time counter initializes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * the time tracking and returns an undefined result.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static u64 timecounter_read_delta(struct timecounter *tc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u64 cycle_now, cycle_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u64 ns_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* read cycle counter: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) cycle_now = tc->cc->read(tc->cc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* calculate the delta since the last timecounter_read_delta(): */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* convert to nanoseconds: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) tc->mask, &tc->frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* update time stamp of timecounter_read_delta() call: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) tc->cycle_last = cycle_now;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return ns_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u64 timecounter_read(struct timecounter *tc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) u64 nsec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* increment time by nanoseconds since last call */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) nsec = timecounter_read_delta(tc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) nsec += tc->nsec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) tc->nsec = nsec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return nsec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) EXPORT_SYMBOL_GPL(timecounter_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * This is like cyclecounter_cyc2ns(), but it is used for computing a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * time previous to the time stored in the cycle counter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static u64 cc_cyc2ns_backwards(const struct cyclecounter *cc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u64 cycles, u64 mask, u64 frac)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) u64 ns = (u64) cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ns = ((ns * cc->mult) - frac) >> cc->shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return ns;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u64 timecounter_cyc2time(struct timecounter *tc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) u64 cycle_tstamp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) u64 delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u64 nsec = tc->nsec, frac = tc->frac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * Instead of always treating cycle_tstamp as more recent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * than tc->cycle_last, detect when it is too far in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * future and treat it as old time stamp instead.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (delta > tc->cc->mask / 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) nsec -= cc_cyc2ns_backwards(tc->cc, delta, tc->mask, frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) nsec += cyclecounter_cyc2ns(tc->cc, delta, tc->mask, &frac);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return nsec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) EXPORT_SYMBOL_GPL(timecounter_cyc2time);