All of lore.kernel.org
 help / color / mirror / Atom feed
From: christopher.s.hall@intel.com
To: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	tglx@linutronix.de, hpa@zytor.com, mingo@redhat.com,
	x86@kernel.org, jacob.e.keller@intel.com,
	richardcochran@gmail.com, davem@davemloft.net,
	sean.v.kelley@intel.com
Cc: Christopher Hall <christopher.s.hall@intel.com>
Subject: [Intel PMC TGPIO Driver 4/5] x86/tsc: Add TSC support functions to support ART driven Time-Aware GPIO
Date: Wed, 11 Dec 2019 13:48:51 -0800	[thread overview]
Message-ID: <20191211214852.26317-5-christopher.s.hall@intel.com> (raw)
In-Reply-To: <20191211214852.26317-1-christopher.s.hall@intel.com>

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

The PMC Time-Aware GPIO (TGPIO) logic is driven by ART. Several support
functions are required to translate ART to/from nanoseconds units which
is required by the PHC clock interface. A function is also added to get
the current value of ART/TSC using get_cycles() (RDTSC). This avoids
multiple MMIO reads required to retrieve ART.

Note that rather than ART nanoseconds, TSC nanoseconds are used. These are
related by TSC = ART * CPUID[15H].EBX/CPUID[15H].EAX + K. The value of
K is the distinction between between the ART and TSC nanoseconds.

The advantage of using TSC nanoseconds to represent the device clock
because it can easily be calculated in user-space using only CPUID[15H].
The value of ART in general can't be since K isn't necessarily known to
the application.

Signed-off-by: Christopher Hall <christopher.s.hall@intel.com>
---
 arch/x86/include/asm/tsc.h |   6 ++
 arch/x86/kernel/tsc.c      | 116 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 8a0c25c6bf09..f44c92fe3cd5 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -32,6 +32,12 @@ static inline cycles_t get_cycles(void)
 
 extern struct system_counterval_t convert_art_to_tsc(u64 art);
 extern struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns);
+extern struct timespec64 get_tsc_ns_now(struct system_counterval_t
+					*system_counter);
+extern u64 convert_tsc_ns_to_art(struct timespec64 *tsc_ns);
+extern u64 convert_tsc_ns_to_art_duration(struct timespec64 *tsc_ns);
+extern struct timespec64 convert_art_to_tsc_ns(u64 art);
+extern struct timespec64 convert_art_to_tsc_ns_duration(u64 art);
 
 extern void tsc_early_init(void);
 extern void tsc_init(void);
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 7e322e2daaf5..fb0dc3169e6b 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -1215,7 +1215,7 @@ int unsynchronized_tsc(void)
 /*
  * Convert ART to TSC given numerator/denominator found in detect_art()
  */
-struct system_counterval_t convert_art_to_tsc(u64 art)
+static struct system_counterval_t _convert_art_to_tsc(u64 art, bool dur)
 {
 	u64 tmp, res, rem;
 
@@ -1225,13 +1225,125 @@ struct system_counterval_t convert_art_to_tsc(u64 art)
 	tmp = rem * art_to_tsc_numerator;
 
 	do_div(tmp, art_to_tsc_denominator);
-	res += tmp + art_to_tsc_offset;
+	res += tmp;
+	if (!dur)
+		res += art_to_tsc_offset;
 
 	return (struct system_counterval_t) {.cs = art_related_clocksource,
 			.cycles = res};
 }
+
+struct system_counterval_t convert_art_to_tsc(u64 art)
+{
+	return _convert_art_to_tsc(art, false);
+}
 EXPORT_SYMBOL(convert_art_to_tsc);
 
+static
+struct timespec64 get_tsc_ns(struct system_counterval_t *system_counter)
+{
+	u64 tmp, res, rem;
+	u64 cycles;
+
+	cycles = system_counter->cycles;
+	rem = do_div(cycles, tsc_khz);
+
+	res = cycles * USEC_PER_SEC;
+	tmp = rem * USEC_PER_SEC;
+
+	rem = do_div(tmp, tsc_khz);
+	tmp += rem > tsc_khz >> 2 ? 1 : 0;
+	res += tmp;
+
+	rem = do_div(res, NSEC_PER_SEC);
+
+	return (struct timespec64) {.tv_sec = res, .tv_nsec = rem};
+}
+
+struct timespec64 get_tsc_ns_now(struct system_counterval_t *system_counter)
+{
+	struct system_counterval_t counterval;
+
+	if (system_counter == NULL)
+		system_counter = &counterval;
+
+	system_counter->cycles = clocksource_tsc.read(NULL);
+	system_counter->cs = art_related_clocksource;
+
+	return get_tsc_ns(system_counter);
+}
+EXPORT_SYMBOL(get_tsc_ns_now);
+
+struct timespec64 convert_art_to_tsc_ns(u64 art)
+{
+	struct system_counterval_t counterval;
+
+	counterval = _convert_art_to_tsc(art, false);
+
+	return get_tsc_ns(&counterval);
+}
+EXPORT_SYMBOL(convert_art_to_tsc_ns);
+
+struct timespec64 convert_art_to_tsc_ns_duration(u64 art)
+{
+	struct system_counterval_t counterval;
+
+	counterval = _convert_art_to_tsc(art, true);
+
+	return get_tsc_ns(&counterval);
+}
+EXPORT_SYMBOL(convert_art_to_tsc_ns_duration);
+
+static u64 convert_tsc_ns_to_tsc(struct timespec64 *tsc_ns)
+{
+	u64 tmp, res, rem;
+	u64 cycles;
+
+	cycles = timespec64_to_ns(tsc_ns);
+
+	rem = do_div(cycles, USEC_PER_SEC);
+
+	res = cycles * tsc_khz;
+	tmp = rem * tsc_khz;
+
+	do_div(tmp, USEC_PER_SEC);
+
+	return res + tmp;
+}
+
+
+static u64 _convert_tsc_ns_to_art(struct timespec64 *tsc_ns, bool dur)
+{
+	u64 tmp, res, rem;
+	u64 cycles;
+
+	cycles = convert_tsc_ns_to_tsc(tsc_ns);
+	if (!dur)
+		cycles -= art_to_tsc_offset;
+
+	rem = do_div(cycles, art_to_tsc_numerator);
+
+	res = cycles * art_to_tsc_denominator;
+	tmp = rem * art_to_tsc_denominator;
+
+	rem = do_div(tmp, art_to_tsc_numerator);
+	tmp += rem > art_to_tsc_numerator >> 2 ? 1 : 0;
+
+	return res + tmp;
+}
+
+u64 convert_tsc_ns_to_art(struct timespec64 *tsc_ns)
+{
+	return _convert_tsc_ns_to_art(tsc_ns, false);
+}
+EXPORT_SYMBOL(convert_tsc_ns_to_art);
+
+u64 convert_tsc_ns_to_art_duration(struct timespec64 *tsc_ns)
+{
+	return _convert_tsc_ns_to_art(tsc_ns, true);
+}
+EXPORT_SYMBOL(convert_tsc_ns_to_art_duration);
+
 /**
  * convert_art_ns_to_tsc() - Convert ART in nanoseconds to TSC.
  * @art_ns: ART (Always Running Timer) in unit of nanoseconds
-- 
2.21.0


  parent reply	other threads:[~2020-01-31  6:41 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-11 21:48 [Intel PMC TGPIO Driver 0/5] Add support for Intel PMC Time GPIO Driver with PHC interface changes to support additional H/W Features christopher.s.hall
2019-12-11 21:48 ` [Intel PMC TGPIO Driver 1/5] drivers/ptp: Add Enhanced handling of reserve fields christopher.s.hall
2020-01-31 16:54   ` Jacob Keller
2020-02-03  1:45     ` Richard Cochran
2020-02-24 23:29       ` Christopher S. Hall
2020-01-31 17:02   ` Jacob Keller
2020-02-03  1:27   ` Richard Cochran
2020-02-24 23:23     ` Christopher S. Hall
2019-12-11 21:48 ` [Intel PMC TGPIO Driver 2/5] drivers/ptp: Add PEROUT2 ioctl frequency adjustment interface christopher.s.hall
2020-02-03  2:14   ` Richard Cochran
2020-02-26  0:20     ` Christopher S. Hall
2019-12-11 21:48 ` [Intel PMC TGPIO Driver 3/5] drivers/ptp: Add user-space input polling interface christopher.s.hall
2020-02-03  2:28   ` Richard Cochran
2019-12-11 21:48 ` christopher.s.hall [this message]
2019-12-11 21:48 ` [Intel PMC TGPIO Driver 5/5] drivers/ptp: Add PMC Time-Aware GPIO Driver christopher.s.hall
2020-02-03  2:31   ` Richard Cochran
2020-02-07 17:10   ` Linus Walleij
2020-02-07 17:28     ` Andrew Lunn
2020-02-07 19:49       ` Andy Shevchenko
2020-02-07 19:52         ` Andy Shevchenko
2020-02-24 23:17     ` Christopher S. Hall
2020-01-31 15:08 ` [Intel PMC TGPIO Driver 0/5] Add support for Intel PMC Time GPIO Driver with PHC interface changes to support additional H/W Features Jakub Kicinski
2020-01-31 18:14 ` Thomas Gleixner
2020-02-24 22:40   ` Christopher S. Hall
2020-02-26 23:06     ` Thomas Gleixner
2020-03-03  1:56       ` Christopher S. Hall
2020-03-03 13:00       ` Linus Walleij
2020-03-03 15:23         ` Richard Cochran
2020-03-03 15:24         ` Thomas Gleixner
2020-03-08 19:14           ` Jonathan Cameron
2020-02-03  4:08 ` Richard Cochran
2020-02-03 18:27   ` Jacob Keller
2020-02-25 23:37   ` Christopher S. Hall
2020-02-26  2:47     ` Richard Cochran
2020-03-03  2:01       ` Christopher S. Hall
2020-02-07 17:17 ` Linus Walleij

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191211214852.26317-5-christopher.s.hall@intel.com \
    --to=christopher.s.hall@intel.com \
    --cc=davem@davemloft.net \
    --cc=hpa@zytor.com \
    --cc=jacob.e.keller@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=richardcochran@gmail.com \
    --cc=sean.v.kelley@intel.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.