All of lore.kernel.org
 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 02/13] extended semantic of sk_buff::tstamp: lowest bit marks hardware time stamps
Date: Wed, 22 Oct 2008 10:17:24 +0200	[thread overview]
Message-ID: <1226415407.31699.1.camel@ecld0pohly> (raw)
In-Reply-To: <1226414697.17450.852.camel@ecld0pohly>

If generated in hardware, then the driver must convert to system
time before storing the transformed value in sk_buff with skb_hwtstamp_set().
If conversion back to the original hardware time stamp is desired,
then the driver needs to implement the hwtstamp_raw() callback, which
is called by skb_hwtstamp_raw().

The purpose of the new skb_* methods is the hiding of how hardware
time stamps are really stored. Later they might be stored in an extra
field instead of mangling the existing tstamp.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
---
 include/linux/netdevice.h |   12 +++++++
 include/linux/skbuff.h    |   76 +++++++++++++++++++++++++++++++++++++++++++-
 net/core/skbuff.c         |   32 +++++++++++++++++++
 3 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 488c56e..4da51cb 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -749,6 +749,18 @@ struct net_device
 	/* for setting kernel sock attribute on TCP connection setup */
 #define GSO_MAX_SIZE		65536
 	unsigned int		gso_max_size;
+
+	/* hardware time stamping support */
+#define HAVE_HW_TIME_STAMP
+	/* Transforms skb->tstamp back to the original, raw hardware
+	 * time stamp. The value must have been generated by the
+	 * device. Implementing this is optional, but necessary for
+	 * SO_TIMESTAMP_HARDWARE.
+	 *
+	 * Returns 1 if value could be retrieved, 0 otherwise.
+	 */
+	int                     (*hwtstamp_raw)(const struct sk_buff *skb,
+						struct timespec *stamp);
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9099237..0b3b36a 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -199,7 +199,10 @@ typedef unsigned char *sk_buff_data_t;
  *	@next: Next buffer in list
  *	@prev: Previous buffer in list
  *	@sk: Socket we are owned by
- *	@tstamp: Time we arrived
+ *	@tstamp: Time we arrived: usually generated by ktime_get_real() and
+ *               thus is recorded in system time. If the lowest bit is set,
+ *               then the value was originally generated by a different clock
+ *               in the receiving hardware and then transformed to system time.
  *	@dev: Device we arrived on/are leaving by
  *	@transport_header: Transport layer header
  *	@network_header: Network layer header
@@ -1524,23 +1527,52 @@ static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
 
 extern void skb_init(void);
 
+/** returns skb->tstamp without the bit which marks hardware time stamps */
+static inline union ktime skb_get_ktime(const struct sk_buff *skb)
+{
+#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
+	return ktime_set(skb->tstamp.tv.sec,
+			skb->tstamp.tv.nsec & ~1);
+#else
+	return (ktime_t) { .tv64 = skb->tstamp.tv64 & ~1UL };
+#endif
+}
+
 /**
  *	skb_get_timestamp - get timestamp from a skb
  *	@skb: skb to get stamp from
  *	@stamp: pointer to struct timeval to store stamp in
  *
  *	Timestamps are stored in the skb as offsets to a base timestamp.
+ *      The lowest bit is set if and only if the time stamp was originally
+ *      created by hardware when processing the packet.
+ *
  *	This function converts the offset back to a struct timeval and stores
  *	it in stamp.
  */
 static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
 {
-	*stamp = ktime_to_timeval(skb->tstamp);
+	*stamp = ktime_to_timeval(skb_get_ktime(skb));
+}
+
+static inline void skb_get_timestampns(const struct sk_buff *skb, struct timespec *stamp)
+{
+	*stamp = ktime_to_timespec(skb_get_ktime(skb));
 }
 
 static inline void __net_timestamp(struct sk_buff *skb)
 {
 	skb->tstamp = ktime_get_real();
+
+	/*
+	 * make sure that lowest bit is never set: it marks hardware
+	 * time stamps
+	 */
+#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
+	skb->tstamp.tv.sec = skb->tstamp.tv.sec / 2 * 2;
+#else
+	skb->tstamp.tv64 = skb->tstamp.tv64 / 2 * 2;
+#endif
 }
 
 static inline ktime_t net_timedelta(ktime_t t)
@@ -1553,6 +1585,46 @@ static inline ktime_t net_invalid_timestamp(void)
 	return ktime_set(0, 0);
 }
 
+/**
+ * checks whether the time stamp value has been set (= non-zero)
+ * and really came from hardware
+ */
+static inline int skb_hwtstamp_available(const struct sk_buff *skb)
+{
+	return skb->tstamp.tv64 & 1;
+}
+
+static inline void skb_hwtstamp_set(struct sk_buff *skb,
+				union ktime stamp)
+{
+#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
+	skb->tstamp.tv.sec = stamp.tv.sec;
+	skb->tstamp.tv.nsec = stamp.tv.nsec | 1;
+#else
+	skb->tstamp.tv64 = stamp.tv64 | 1;
+#endif
+}
+
+/**
+ * Fills the timespec with the original, "raw" time stamp as generated
+ * by the hardware when it processed the packet and returns 1 if such
+ * a hardware time stamp is unavailable or cannot be inferred. Otherwise
+ * it returns 0;
+ */
+int skb_hwtstamp_raw(const struct sk_buff *skb, struct timespec *stamp);
+
+/**
+ * Fills the timespec with the hardware time stamp generated when the
+ * hardware processed the packet, transformed to system time. Beware
+ * that this transformation is not perfect: packet A received on
+ * interface 1 before packet B on interface 2 might have a higher
+ * transformed time stamp.
+ *
+ * Returns 1 if a transformed hardware time stamp is available, 0
+ * otherwise.
+ */
+int skb_hwtstamp_transformed(const struct sk_buff *skb, struct timespec *stamp);
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index ca1ccdf..7a95062 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -44,6 +44,7 @@
 #include <linux/in.h>
 #include <linux/inet.h>
 #include <linux/slab.h>
+#include <linux/inetdevice.h>
 #include <linux/netdevice.h>
 #ifdef CONFIG_NET_CLS_ACT
 #include <net/pkt_sched.h>
@@ -2323,6 +2324,37 @@ err:
 
 EXPORT_SYMBOL_GPL(skb_segment);
 
+int skb_hwtstamp_raw(const struct sk_buff *skb, struct timespec *stamp)
+{
+	struct rtable *rt;
+	struct in_device *idev;
+	struct net_device *netdev;
+
+	if (skb_hwtstamp_available(skb) &&
+	    (rt = skb->rtable) != NULL &&
+	    (idev = rt->idev) != NULL &&
+	    (netdev = idev->dev) != NULL  &&
+	    netdev->hwtstamp_raw) {
+		return netdev->hwtstamp_raw(skb, stamp);
+	} else {
+		return 0;
+	}
+}
+
+EXPORT_SYMBOL_GPL(skb_hwtstamp_raw);
+
+int skb_hwtstamp_transformed(const struct sk_buff *skb, struct timespec *stamp)
+{
+        if (skb_hwtstamp_available(skb)) {
+		skb_get_timestampns(skb, stamp);
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+EXPORT_SYMBOL_GPL(skb_hwtstamp_transformed);
+
 void __init skb_init(void)
 {
 	skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
-- 
1.6.0.4



  reply	other threads:[~2008-11-11 14:56 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 ` Patrick Ohly [this message]
2008-11-12  7:41   ` [RFC PATCH 02/13] extended semantic of sk_buff::tstamp: lowest bit marks hardware time stamps 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 ` [RFC PATCH 09/13] clocksource: allow usage independent of timekeeping.c Patrick Ohly
2008-11-12 10:04   ` 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=1226415407.31699.1.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 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.