netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Patrick Ohly <patrick.ohly@intel.com>
To: netdev@vger.kernel.org
Cc: Octavian Purdila <opurdila@ixiacom.com>,
	Stephen Hemminger <shemminger@vyatta.com>,
	Ingo Oeser <netdev@axxeo.de>, Andi Kleen <ak@linux.intel.com>,
	John Ronciak <john.ronciak@intel.com>,
	Eric Dumazet <dada1@cosmosbay.com>,
	Oliver Hartkopp <oliver@hartkopp.net>
Subject: [RFC PATCH 09/13] clocksource: allow usage independent of timekeeping.c
Date: Tue, 4 Nov 2008 10:23:42 +0100	[thread overview]
Message-ID: <1226415438.31699.8.camel@ecld0pohly> (raw)
In-Reply-To: <1226414697.17450.852.camel@ecld0pohly>

So far struct clocksource acted as the interface between time/timekeeping
and hardware. This patch generalizes the concept so that the same
interface can also be used in other contexts.

The only change as far as kernel/time/timekeeping is concerned is that
the hardware access can be done either with or without passing
the clocksource pointer as context. This is necessary in those
cases when there is more than one instance of the hardware.

The extensions in this patch add code which turns the raw cycle count
provided by hardware into a continously increasing time value. This
reuses fields also used by timekeeping.c. Because of slightly different
semantic (__get_nsec_offset does not update cycle_last, clocksource_read_ns
does that transparently) timekeeping.c was not modified to use the
generalized code.

The new code does no locking of the clocksource. This is the responsibility
of the caller.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
---
 include/linux/clocksource.h |  119 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 118 insertions(+), 1 deletions(-)

diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 55e434f..da4c7cd 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -24,6 +24,9 @@ struct clocksource;
 /**
  * struct clocksource - hardware abstraction for a free running counter
  *	Provides mostly state-free accessors to the underlying hardware.
+ *      Also provides utility functions which convert the underlying
+ *      hardware cycle values into a non-decreasing count of nanoseconds
+ *      ("time").
  *
  * @name:		ptr to clocksource name
  * @list:		list head for registration
@@ -43,6 +46,9 @@ struct clocksource;
  *				The ideal clocksource. A must-use where
  *				available.
  * @read:		returns a cycle value
+ * @read_clock:         alternative to read which gets a pointer to the clock
+ *                      source so that the same code can read different clocks;
+ *                      either read or read_clock must be set
  * @mask:		bitmask for two's complement
  *			subtraction of non 64 bit counters
  * @mult:		cycle to nanosecond multiplier
@@ -61,6 +67,7 @@ struct clocksource {
 	struct list_head list;
 	int rating;
 	cycle_t (*read)(void);
+	cycle_t (*read_clock)(struct clocksource *cs);
 	cycle_t mask;
 	u32 mult;
 	u32 shift;
@@ -166,7 +173,7 @@ static inline u32 clocksource_hz2mult(u32 hz, u32 shift_constant)
  */
 static inline cycle_t clocksource_read(struct clocksource *cs)
 {
-	return cs->read();
+	return (cs->read ? cs->read() : cs->read_clock(cs));
 }
 
 /**
@@ -186,6 +193,116 @@ static inline s64 cyc2ns(struct clocksource *cs, cycle_t cycles)
 }
 
 /**
+ * clocksource_read_ns - get nanoseconds since last call of this function
+ *                       (never negative)
+ * @cs:         Pointer to clocksource
+ *
+ * When the underlying cycle counter runs over, this will be handled
+ * correctly as long as it does not run over more than once between
+ * calls.
+ *
+ * The first call to this function for a new clock source initializes
+ * the time tracking and returns bogus results.
+ */
+static inline s64 clocksource_read_ns(struct clocksource *cs)
+{
+	cycle_t cycle_now, cycle_delta;
+	s64 ns_offset;
+
+	/* read clocksource: */
+	cycle_now = clocksource_read(cs);
+
+	/* calculate the delta since the last clocksource_read_ns: */
+	cycle_delta = (cycle_now - cs->cycle_last) & cs->mask;
+
+	/* convert to nanoseconds: */
+	ns_offset = cyc2ns(cs, cycle_delta);
+
+	/* update time stamp of clocksource_read_ns call: */
+	cs->cycle_last = cycle_now;
+
+	return ns_offset;
+}
+
+/**
+ * clocksource_init_time - initialize a clock source for use with
+ *                         %clocksource_read_time() and
+ *                         %clocksource_cyc2time()
+ * @cs:            Pointer to clocksource.
+ * @start_tstamp:  Arbitrary initial time stamp.
+ *
+ * After this call the current cycle register (roughly) corresponds to
+ * the initial time stamp. Every call to %clocksource_read_time()
+ * increments the time stamp counter by the number of elapsed
+ * nanoseconds.
+ */
+static inline void clocksource_init_time(struct clocksource *cs,
+					u64 start_tstamp)
+{
+	cs->cycle_last = clocksource_read(cs);
+	cs->xtime_nsec = start_tstamp;
+}
+
+/**
+ * clocksource_read_time - return nanoseconds since %clocksource_init_time()
+ *                         plus the initial time stamp
+ * @cs:          Pointer to clocksource.
+ *
+ * In other words, keeps track of time since the same epoch as
+ * the function which generated the initial time stamp. Don't mix
+ * with calls to %clocksource_read_ns()!
+ */
+static inline u64 clocksource_read_time(struct clocksource *cs)
+{
+	u64 nsec;
+
+	/* increment time by nanoseconds since last call */
+	nsec = clocksource_read_ns(cs);
+	nsec += cs->xtime_nsec;
+	cs->xtime_nsec = nsec;
+
+	return nsec;
+}
+
+/**
+ * clocksource_cyc2time - convert an absolute cycle time stamp to same
+ *                        time base as values returned by
+ *                        %clocksource_read_time()
+ * @cs:            Pointer to clocksource.
+ * @cycle_tstamp:  a value returned by cs->read()
+ *
+ * Cycle time stamps that are converted correctly as long as they
+ * fall into the time interval [-1/2 max cycle count, 1/2 cycle count],
+ * with "max cycle count" == cs->mask+1.
+ *
+ * This avoids situations where a cycle time stamp is generated, the
+ * current cycle counter is updated, and then when transforming the
+ * time stamp the value is treated as if it was in the future. Always
+ * updating the cycle counter would also work, but incurr additional
+ * overhead.
+ */
+static inline u64 clocksource_cyc2time(struct clocksource *cs,
+				cycle_t cycle_tstamp)
+{
+	u64 cycle_delta = (cycle_tstamp - cs->cycle_last) & cs->mask;
+	u64 nsec;
+
+	/*
+	 * Instead of always treating cycle_tstamp as more recent
+	 * than cs->cycle_last, detect when it is too far in the
+	 * future and treat it as old time stamp instead.
+	 */
+	if (cycle_delta > cs->mask / 2) {
+		cycle_delta = (cs->cycle_last - cycle_tstamp) & cs->mask;
+		nsec = cs->xtime_nsec - cyc2ns(cs, cycle_delta);
+	} else {
+		nsec = cyc2ns(cs, cycle_delta) + cs->xtime_nsec;
+	}
+
+	return nsec;
+}
+
+/**
  * clocksource_calculate_interval - Calculates a clocksource interval struct
  *
  * @c:		Pointer to clocksource.
-- 
1.6.0.4



  parent reply	other threads:[~2008-11-11 14:57 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-11-11 14:44 [RFC PATCH 00/13] hardware time stamping + igb example implementation Patrick Ohly
2008-10-22  8:17 ` [RFC PATCH 02/13] extended semantic of sk_buff::tstamp: lowest bit marks hardware time stamps Patrick Ohly
2008-11-12  7:41   ` Eric Dumazet
2008-11-12  8:09     ` Patrick Ohly
2008-11-12 10:09       ` David Miller
2008-11-12  9:58   ` David Miller
2008-11-19 12:50     ` Patrick Ohly
2008-10-22 12:46 ` [RFC PATCH 01/13] put_cmsg_compat + SO_TIMESTAMP[NS]: use same name for value as caller Patrick Ohly
2008-11-12  9:55   ` David Miller
2008-10-22 15:01 ` [RFC PATCH 03/13] user space API for time stamping of incoming and outgoing packets Patrick Ohly
2008-11-12 10:02   ` David Miller
2008-10-24 13:41 ` [RFC PATCH 04/13] net: implement generic SOF_TIMESTAMPING_TX_* support Patrick Ohly
2008-11-11 23:15   ` Octavian Purdila
2008-11-12  8:38     ` Patrick Ohly
2008-10-24 13:49 ` [RFC PATCH 05/13] ip: support for TX timestamps on UDP and RAW sockets Patrick Ohly
2008-11-12  9:59   ` David Miller
2008-10-29 14:48 ` [RFC PATCH 06/13] workaround: detect time stamp when command flags are expected Patrick Ohly
2008-11-12 10:00   ` David Miller
2008-10-31 11:43 ` [RFC PATCH 07/13] net: add SIOCSHWTSTAMP - hardware time stamping of packets Patrick Ohly
2008-10-31 12:21 ` [RFC PATCH 08/13] igb: stub support for SIOCSHWTSTAMP Patrick Ohly
2008-11-04  9:23 ` Patrick Ohly [this message]
2008-11-12 10:04   ` [RFC PATCH 09/13] clocksource: allow usage independent of timekeeping.c David Miller
2008-11-04  9:27 ` [RFC PATCH 10/13] igb: infrastructure for hardware time stamping Patrick Ohly
2008-11-05  9:58 ` [RFC PATCH 11/13] time sync: generic infrastructure to map between time stamps generated by a clock source and system time Patrick Ohly
2008-11-11 16:18   ` Andi Kleen
2008-11-12  8:01     ` Patrick Ohly
2008-11-12 10:08       ` David Miller
2008-11-12 16:14         ` Patrick Ohly
2008-11-12 16:28           ` Eric Dumazet
2008-11-12 10:05   ` David Miller
2008-11-06 11:13 ` [RFC PATCH 12/13] igb: use clocksync to implement hardware time stamping Patrick Ohly
2008-11-07  9:26 ` [RFC PATCH 13/13] skbuff: optionally store hardware time stamps in new field Patrick Ohly
2008-11-12 16:06 ` [RFC PATCH 00/13] hardware time stamping + igb example implementation Andi Kleen
2008-11-12 16:25   ` Patrick Ohly
2008-11-12 18:44     ` Oliver Hartkopp
2008-11-12 19:22       ` Eric Dumazet
2008-11-12 20:23         ` Andi Kleen
2008-11-12 20:23         ` Andi Kleen
2008-11-12 20:56           ` Eric Dumazet
2008-11-12 21:34             ` Andi Kleen
2008-11-12 22:26               ` Oliver Hartkopp
2008-11-13 15:53                 ` Ohly, Patrick
2008-11-13  6:15               ` Oliver Hartkopp
2008-11-13  6:29                 ` Eric Dumazet
2008-11-13 16:05                 ` Ohly, Patrick
2008-11-16  8:15               ` Andrew Shewmaker
2008-11-12 22:17           ` David Miller
2008-11-19 12:39       ` Patrick Ohly

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=1226415438.31699.8.camel@ecld0pohly \
    --to=patrick.ohly@intel.com \
    --cc=ak@linux.intel.com \
    --cc=dada1@cosmosbay.com \
    --cc=john.ronciak@intel.com \
    --cc=netdev@axxeo.de \
    --cc=netdev@vger.kernel.org \
    --cc=oliver@hartkopp.net \
    --cc=opurdila@ixiacom.com \
    --cc=shemminger@vyatta.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).