From mboxrd@z Thu Jan 1 00:00:00 1970 From: Eric Dumazet Subject: Re: [RFC PATCH 02/13] extended semantic of sk_buff::tstamp: lowest bit marks hardware time stamps Date: Wed, 12 Nov 2008 08:41:31 +0100 Message-ID: <491A88AB.8070006@cosmosbay.com> References: <1226414697.17450.852.camel@ecld0pohly> <1226415407.31699.1.camel@ecld0pohly> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: netdev@vger.kernel.org, Octavian Purdila , Stephen Hemminger , Ingo Oeser , Andi Kleen , John Ronciak , Oliver Hartkopp To: Patrick Ohly Return-path: Received: from gw1.cosmosbay.com ([86.65.150.130]:58197 "EHLO gw1.cosmosbay.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751022AbYKLHls convert rfc822-to-8bit (ORCPT ); Wed, 12 Nov 2008 02:41:48 -0500 In-Reply-To: <1226415407.31699.1.camel@ecld0pohly> Sender: netdev-owner@vger.kernel.org List-ID: Patrick Ohly a =E9crit : > If generated in hardware, then the driver must convert to system > time before storing the transformed value in sk_buff with skb_hwtstam= p_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(). >=20 > 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. >=20 > Signed-off-by: Patrick Ohly > --- > include/linux/netdevice.h | 12 +++++++ > include/linux/skbuff.h | 76 +++++++++++++++++++++++++++++++++++= ++++++++- > net/core/skbuff.c | 32 +++++++++++++++++++ > 3 files changed, 118 insertions(+), 2 deletions(-) >=20 > 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) > =20 > 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() a= nd > + * thus is recorded in system time. If the lowest bit = is set, > + * then the value was originally generated by a differ= ent clock > + * in the receiving hardware and then transformed to s= ystem 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_of= fset(struct sk_buff *skb, > =20 > extern void skb_init(void); Please use ktime_t instead of "union ktime" > =20 > +/** returns skb->tstamp without the bit which marks hardware time st= amps */ > +static inline union ktime skb_get_ktime(const struct sk_buff *skb) > +{ > +#if BITS_PER_LONG !=3D 64 && !defined(CONFIG_KTIME_SCALAR) > + return ktime_set(skb->tstamp.tv.sec, > + skb->tstamp.tv.nsec & ~1); > +#else > + return (ktime_t) { .tv64 =3D 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 orig= inally > + * created by hardware when processing the packet. > + * > * This function converts the offset back to a struct timeval and st= ores > * it in stamp. > */ > static inline void skb_get_timestamp(const struct sk_buff *skb, stru= ct timeval *stamp) > { > - *stamp =3D ktime_to_timeval(skb->tstamp); > + *stamp =3D ktime_to_timeval(skb_get_ktime(skb)); > +} > + > +static inline void skb_get_timestampns(const struct sk_buff *skb, st= ruct timespec *stamp) > +{ > + *stamp =3D ktime_to_timespec(skb_get_ktime(skb)); > } > =20 > static inline void __net_timestamp(struct sk_buff *skb) > { > skb->tstamp =3D ktime_get_real(); > + > + /* > + * make sure that lowest bit is never set: it marks hardware > + * time stamps > + */ > +#if BITS_PER_LONG !=3D 64 && !defined(CONFIG_KTIME_SCALAR) > + skb->tstamp.tv.sec =3D skb->tstamp.tv.sec / 2 * 2; =2Etv.sec ? are you sure you dont want .tv.nsec ? > +#else > + skb->tstamp.tv64 =3D skb->tstamp.tv64 / 2 * 2; > +#endif > } > =20