Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Based on clocksource code. See commit 74d23cc704d1
0004  */
0005 #include <linux/export.h>
0006 #include <linux/timecounter.h>
0007 
0008 void timecounter_init(struct timecounter *tc,
0009               const struct cyclecounter *cc,
0010               u64 start_tstamp)
0011 {
0012     tc->cc = cc;
0013     tc->cycle_last = cc->read(cc);
0014     tc->nsec = start_tstamp;
0015     tc->mask = (1ULL << cc->shift) - 1;
0016     tc->frac = 0;
0017 }
0018 EXPORT_SYMBOL_GPL(timecounter_init);
0019 
0020 /**
0021  * timecounter_read_delta - get nanoseconds since last call of this function
0022  * @tc:         Pointer to time counter
0023  *
0024  * When the underlying cycle counter runs over, this will be handled
0025  * correctly as long as it does not run over more than once between
0026  * calls.
0027  *
0028  * The first call to this function for a new time counter initializes
0029  * the time tracking and returns an undefined result.
0030  */
0031 static u64 timecounter_read_delta(struct timecounter *tc)
0032 {
0033     u64 cycle_now, cycle_delta;
0034     u64 ns_offset;
0035 
0036     /* read cycle counter: */
0037     cycle_now = tc->cc->read(tc->cc);
0038 
0039     /* calculate the delta since the last timecounter_read_delta(): */
0040     cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
0041 
0042     /* convert to nanoseconds: */
0043     ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta,
0044                     tc->mask, &tc->frac);
0045 
0046     /* update time stamp of timecounter_read_delta() call: */
0047     tc->cycle_last = cycle_now;
0048 
0049     return ns_offset;
0050 }
0051 
0052 u64 timecounter_read(struct timecounter *tc)
0053 {
0054     u64 nsec;
0055 
0056     /* increment time by nanoseconds since last call */
0057     nsec = timecounter_read_delta(tc);
0058     nsec += tc->nsec;
0059     tc->nsec = nsec;
0060 
0061     return nsec;
0062 }
0063 EXPORT_SYMBOL_GPL(timecounter_read);
0064 
0065 /*
0066  * This is like cyclecounter_cyc2ns(), but it is used for computing a
0067  * time previous to the time stored in the cycle counter.
0068  */
0069 static u64 cc_cyc2ns_backwards(const struct cyclecounter *cc,
0070                    u64 cycles, u64 mask, u64 frac)
0071 {
0072     u64 ns = (u64) cycles;
0073 
0074     ns = ((ns * cc->mult) - frac) >> cc->shift;
0075 
0076     return ns;
0077 }
0078 
0079 u64 timecounter_cyc2time(const struct timecounter *tc,
0080              u64 cycle_tstamp)
0081 {
0082     u64 delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask;
0083     u64 nsec = tc->nsec, frac = tc->frac;
0084 
0085     /*
0086      * Instead of always treating cycle_tstamp as more recent
0087      * than tc->cycle_last, detect when it is too far in the
0088      * future and treat it as old time stamp instead.
0089      */
0090     if (delta > tc->cc->mask / 2) {
0091         delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask;
0092         nsec -= cc_cyc2ns_backwards(tc->cc, delta, tc->mask, frac);
0093     } else {
0094         nsec += cyclecounter_cyc2ns(tc->cc, delta, tc->mask, &frac);
0095     }
0096 
0097     return nsec;
0098 }
0099 EXPORT_SYMBOL_GPL(timecounter_cyc2time);