diff mbox series

[RFC,v1,08/20] kernel: time: Add system time to system counter translation

Message ID 20210824164801.28896-9-lakshmi.sowjanya.d@intel.com
State New
Headers show
Series Review Request: Add support for Intel PMC | expand

Commit Message

D, Lakshmi Sowjanya Aug. 24, 2021, 4:47 p.m. UTC
From: Christopher Hall <christopher.s.hall@intel.com>

The GPIOlib event generation interface supplies a time in terms of the
realtime system clock. The driver must translate the system clock to
something meaningful to the hardware.

The Intel(R) PMC Timed I/O hardware uses ART to trigger events. For
most Intel(R) platforms that use TSC for timekeeping this added
function translates from system clock to TSC. The relation between TSC
and ART is easily derived from CPUID[15H].

Signed-off-by: Christopher Hall <christopher.s.hall@intel.com>
Signed-off-by: Tamal Saha <tamal.saha@intel.com>
Signed-off-by: Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>
Reviewed-by: Mark Gross <mgross@linux.intel.com>
---
 include/linux/timekeeping.h |  3 ++
 kernel/time/timekeeping.c   | 63 +++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

Comments

Linus Walleij Sept. 16, 2021, 9:48 p.m. UTC | #1
On Tue, Aug 24, 2021 at 6:48 PM <lakshmi.sowjanya.d@intel.com> wrote:

> From: Christopher Hall <christopher.s.hall@intel.com>

>

> The GPIOlib event generation interface supplies a time in terms of the

> realtime system clock. The driver must translate the system clock to

> something meaningful to the hardware.

>

> The Intel(R) PMC Timed I/O hardware uses ART to trigger events. For

> most Intel(R) platforms that use TSC for timekeeping this added

> function translates from system clock to TSC. The relation between TSC

> and ART is easily derived from CPUID[15H].

>

> Signed-off-by: Christopher Hall <christopher.s.hall@intel.com>

> Signed-off-by: Tamal Saha <tamal.saha@intel.com>

> Signed-off-by: Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com>

> Reviewed-by: Mark Gross <mgross@linux.intel.com>


I don't quite understand what this patch does, but it looks very generic.
I think the exact usecase needs to be in the commit message.

In either case, this is a patch TGLX et al needs to look at, we can't
merge timekeeping code without their consent.

Yours,
Linus Walleij
diff mbox series

Patch

diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index 78a98bdff76d..46ee524ca1a0 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -277,6 +277,9 @@  struct system_counterval_t {
 	struct clocksource	*cs;
 };
 
+extern int ktime_convert_real_to_system_counter(ktime_t sys_realtime,
+						struct system_counterval_t *ret);
+
 /*
  * Get cross timestamp between system clock and device clock
  */
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 8a364aa9881a..69e4be8f1bfb 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -369,6 +369,31 @@  static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
 
 /* Timekeeper helper functions. */
 
+#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
+static u32 default_arch_gettimeoffset(void) { return 0; }
+u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset;
+#else
+static inline u32 arch_gettimeoffset(void) { return 0; }
+#endif
+
+static inline u64 timekeeping_ns_delta_to_cycles(const struct tk_read_base *tkr,
+						 u64 nsec)
+{
+	u64 cycles;
+
+	/* If arch requires, subtract get_arch_timeoffset() */
+	cycles = nsec - arch_gettimeoffset();
+
+	if (fls64(cycles) + tkr->shift > sizeof(cycles) * 8)
+		return (typeof(cycles))-1;
+
+	cycles <<= tkr->shift;
+	cycles -= tkr->xtime_nsec;
+	do_div(cycles, tkr->mult);
+
+	return cycles;
+}
+
 static inline u64 timekeeping_delta_to_ns(const struct tk_read_base *tkr, u64 delta)
 {
 	u64 nsec;
@@ -1284,6 +1309,44 @@  int get_device_system_crosststamp(int (*get_time_fn)
 }
 EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
 
+/**
+ * ktime_convert_real_to_system_counter - Convert system time to counter value
+ * @sys_realtime:	REALTIME clock value to convert
+ * @ret:		Computed system counter value with clocksource pointer
+ *
+ * Converts a supplied, future REALTIME clock value to the corresponding
+ *	system counter value. Returns current clock source in 'ret'.
+ */
+int ktime_convert_real_to_system_counter(ktime_t sys_realtime,
+					 struct system_counterval_t *ret)
+{
+	struct timekeeper *tk = &tk_core.timekeeper;
+	u64 ns_delta;
+	ktime_t base_real;
+	unsigned int seq;
+
+	do {
+		seq = read_seqcount_begin(&tk_core.seq);
+
+		base_real = ktime_add(tk->tkr_mono.base,
+				      tk_core.timekeeper.offs_real);
+		if (ktime_compare(sys_realtime, base_real) < 0)
+			return -EINVAL;
+
+		ret->cs = tk->tkr_mono.clock;
+		ns_delta = ktime_to_ns(ktime_sub(sys_realtime, base_real));
+		ret->cycles = timekeeping_ns_delta_to_cycles(&tk->tkr_mono,
+							     ns_delta);
+		if (ret->cycles == (typeof(ret->cycles))-1)
+			return -ERANGE;
+
+		ret->cycles += tk->tkr_mono.cycle_last;
+	} while (read_seqcount_retry(&tk_core.seq, seq));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ktime_convert_real_to_system_counter);
+
 /**
  * do_settimeofday64 - Sets the time of day.
  * @ts:     pointer to the timespec64 variable containing the new time