From: Lakshmi Sowjanya D <lakshmi.sowjany...@intel.com>

PPS(Pulse Per Second) generates signals in realtime, but Timed IO
hardware understands time in base clock reference. Add an interface,
ktime_real_to_base_clock() to convert realtime to base clock.

Convert the base clock to the system clock using convert_base_to_cs() in
get_device_system_crosststamp().

Add the helper function timekeeping_clocksource_has_base(), to check
whether the current clocksource has the same base clock. This will be
used by Timed IO device to check if the base clock is X86_ART(Always
Running Timer).

Co-developed-by: Thomas Gleixner <t...@linutronix.de>
Signed-off-by: Thomas Gleixner <t...@linutronix.de>
Co-developed-by: Christopher S. Hall <christopher.s.h...@intel.com>
Signed-off-by: Christopher S. Hall <christopher.s.h...@intel.com>
Signed-off-by: Lakshmi Sowjanya D <lakshmi.sowjany...@intel.com>
---
 include/linux/timekeeping.h |   6 +++
 kernel/time/timekeeping.c   | 105 +++++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index 7e50cbd97f86..1b2a4a37bf93 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -275,12 +275,18 @@ struct system_device_crosststamp {
  *             timekeeping code to verify comparability of two cycle values.
  *             The default ID, CSID_GENERIC, does not identify a specific
  *             clocksource.
+ * @nsecs:     @cycles is in nanoseconds.
  */
 struct system_counterval_t {
        u64                     cycles;
        enum clocksource_ids    cs_id;
+       bool                    nsecs;
 };
 
+extern bool ktime_real_to_base_clock(ktime_t treal,
+                                    enum clocksource_ids base_id, u64 *cycles);
+extern bool timekeeping_clocksource_has_base(enum clocksource_ids id);
+
 /*
  * Get cross timestamp between system clock and device clock
  */
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index b58dffc58a8f..78836c7712dd 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1193,6 +1193,82 @@ static bool timestamp_in_interval(u64 start, u64 end, 
u64 ts)
        return false;
 }
 
+static bool convert_clock(u64 *val, u32 numerator, u32 denominator)
+{
+       u64 rem, res;
+
+       if (!numerator || !denominator)
+               return false;
+
+       res = div64_u64_rem(*val, denominator, &rem) * numerator;
+       *val = res + div_u64(rem * numerator, denominator);
+       return true;
+}
+
+static bool convert_base_to_cs(struct system_counterval_t *scv)
+{
+       struct clocksource *cs = tk_core.timekeeper.tkr_mono.clock;
+       struct clocksource_base *base = cs->base;
+       u32 num, den;
+
+       /* The timestamp was taken from the time keeper clock source */
+       if (cs->id == scv->cs_id)
+               return true;
+
+       /* Check whether cs_id matches the base clock */
+       if (!base || base->id != scv->cs_id)
+               return false;
+
+       num = scv->nsecs ? cs->freq_khz : base->numerator;
+       den = scv->nsecs ? USEC_PER_SEC : base->denominator;
+
+       convert_clock(&scv->cycles, num, den);
+       scv->cycles += base->offset;
+       return true;
+}
+
+static bool convert_cs_to_base(u64 *cycles, enum clocksource_ids base_id)
+{
+       struct clocksource *cs = tk_core.timekeeper.tkr_mono.clock;
+       struct clocksource_base *base = cs->base;
+
+       /* Check whether base_id matches the base clock */
+       if (!base || base->id != base_id)
+               return false;
+
+       *cycles -= base->offset;
+       if (!convert_clock(cycles, base->denominator, base->numerator))
+               return false;
+       return true;
+}
+
+static u64 convert_ns_to_cs(u64 delta)
+{
+       struct tk_read_base *tkr = &tk_core.timekeeper.tkr_mono;
+
+       return div_u64((delta << tkr->shift) - tkr->xtime_nsec, tkr->mult);
+}
+
+bool ktime_real_to_base_clock(ktime_t treal, enum clocksource_ids base_id, u64 
*cycles)
+{
+       struct timekeeper *tk = &tk_core.timekeeper;
+       unsigned int seq;
+       u64 delta;
+
+       do {
+               seq = read_seqcount_begin(&tk_core.seq);
+               delta = (u64)treal - tk->tkr_mono.base_real;
+               if (delta > tk->tkr_mono.clock->max_idle_ns)
+                       return false;
+               *cycles = tk->tkr_mono.cycle_last + convert_ns_to_cs(delta);
+               if (!convert_cs_to_base(cycles, base_id))
+                       return false;
+       } while (read_seqcount_retry(&tk_core.seq, seq));
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(ktime_real_to_base_clock);
+
 /**
  * get_device_system_crosststamp - Synchronously capture system/device 
timestamp
  * @get_time_fn:       Callback to get simultaneous device time and
@@ -1238,8 +1314,7 @@ int get_device_system_crosststamp(int (*get_time_fn)
                 * system counter value is the same as for the currently
                 * installed timekeeper clocksource
                 */
-               if (system_counterval.cs_id == CSID_GENERIC ||
-                   tk->tkr_mono.clock->id != system_counterval.cs_id)
+               if (!convert_base_to_cs(&system_counterval))
                        return -ENODEV;
                cycles = system_counterval.cycles;
 
@@ -1304,6 +1379,32 @@ int get_device_system_crosststamp(int (*get_time_fn)
 }
 EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
 
+/**
+ * timekeeping_clocksource_has_base - Check whether the current clocksource
+ *     has a base clock
+ * @id:                The clocksource ID to check for
+ *
+ * Note:       The return value is a snapshot which can become invalid right
+ *     after the function returns.
+ *
+ * Return:     true if the timekeeper clocksource has a base clock with @id,
+ *     false otherwise
+ */
+bool timekeeping_clocksource_has_base(enum clocksource_ids id)
+{
+       unsigned int seq;
+       bool ret;
+
+       do {
+               seq = read_seqcount_begin(&tk_core.seq);
+               ret = tk_core.timekeeper.tkr_mono.clock->base ?
+               tk_core.timekeeper.tkr_mono.clock->base->id == id : false;
+       } while (read_seqcount_retry(&tk_core.seq, seq));
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(timekeeping_clocksource_has_base);
+
 /**
  * do_settimeofday64 - Sets the time of day.
  * @ts:     pointer to the timespec64 variable containing the new time
-- 
2.35.3

Reply via email to