Skip to contentSkip to conversation

hardware time stamping with optional structs in data area

RFC PATCH In review Patrick Ohly 6 participants 45 messages Dec 15, 2008 – Feb 4, 2009

Subsystems (20)
lore
Share & tools
lore
#0 lore raw

This is the third iteration of a patch series which adds a user space API for hardware time stamping of network packets and the infrastructure that implements that API. The igb driver is used as example for how a network driver can use this new infrastructure. The patches are based on net-next as of today.

This proposal is based on adding just a short flag field to struct sk_buff itself, with the actual new information stored in the data area if indicated by the flags. This is based on the suggestion by Oliver Hartkopp and modelled after the way how skb_shared_info is stored. The previous two revisions of the patch reused skb->tstamp resp. added skb->hwtstamp.

The latest approach is more flexible: it allows adding more optional information in the future. It turned out to be a bit harder to use by drivers, though. The igb driver allocates the skb for incoming packets in advance. At that time it is not yet known which packets will need the extra space for hardware time stamps. The current example igb patch just allocates that space for all packets, all the time. More efficient solutions would be possible.

The functions which allocate an skb had to be modified so that the new flags can be passed down to __netdev_alloc_skb(). I renamed functions as necessary, so that existing code should continue to work without changes. In sock_alloc_send_skb_flags() (formerly known as sock_alloc_send_skb_pskb()) I removed some dead code (see patch 04/12).

As discussed with John Stultz, the changes to clocksource.[ch] now adds new structures as needed. John, I chose not to add new files for these. Please let me know whether you agree with that approach, see patch 09/12 for details.

The user space API is still as it was designed for the previous two implementations. IMHO this shows that it was flexible enough to cope with changes in the implementation. On the other hand some of its aspects (user space has fine-grained control over what information is gathered and provided by the kernel) might be seen as overkill now that drivers can add this information more easily.

I think the API still makes sense because the additional information might be used for optimizations in the future (drivers could skip time stamp conversion if no-one is interested).

Also fixed in this iteration:
* comment style, too many/large inline functions (pointed out by Andrew Morton)
* __KERNEL__ instead __kernel__, user space API now in linux/net_tstamp.h (David Miller)

Bye, Patrick

 Documentation/networking/timestamping.txt          |  180 ++++++++
 Documentation/networking/timestamping/.gitignore   |    1 +
 Documentation/networking/timestamping/Makefile     |    3 +
 .../networking/timestamping/timestamping.c         |  469 ++++++++++++++++++++
 arch/x86/include/asm/socket.h                      |    3 +
 drivers/net/igb/e1000_82575.h                      |    1 +
 drivers/net/igb/e1000_defines.h                    |    1 +
 drivers/net/igb/e1000_regs.h                       |   68 +++
 drivers/net/igb/igb.h                              |    8 +
 drivers/net/igb/igb_main.c                         |  397 ++++++++++++++++-
 fs/compat_ioctl.c                                  |    1 +
 include/linux/clocksource.h                        |   99 ++++
 include/linux/clocksync.h                          |   85 ++++
 include/linux/errqueue.h                           |    1 +
 include/linux/net_tstamp.h                         |  104 +++++
 include/linux/skbuff.h                             |  196 ++++++++-
 include/linux/sockios.h                            |    3 +
 include/net/ip.h                                   |    1 +
 include/net/sock.h                                 |   57 ++-
 kernel/time/Makefile                               |    2 +-
 kernel/time/clocksource.c                          |   76 ++++
 kernel/time/clocksync.c                            |  182 ++++++++
 net/can/raw.c                                      |   14 +-
 net/compat.c                                       |   19 +-
 net/core/dev.c                                     |   36 ++-
 net/core/skbuff.c                                  |  139 +++++-
 net/core/sock.c                                    |  129 +++---
 net/ipv4/icmp.c                                    |    2 +
 net/ipv4/ip_output.c                               |   18 +-
 net/ipv4/raw.c                                     |    1 +
 net/ipv4/udp.c                                     |    4 +
 net/socket.c                                       |   86 +++-
 32 files changed, 2258 insertions(+), 128 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#1 lore raw

RFC PATCH 1/12 net: new user space API for time stamping of incoming and outgoing packets

User space can request hardware and/or software time stamping. Reporting of the result(s) via a new control message is enabled separately for each field in the message because some of the fields may require additional computation and thus cause overhead. User space can tell the different kinds of time stamps apart and choose what suits its needs.

When a TX timestamp operation is requested, the TX skb will be cloned and the clone will be time stamped (in hardware or software) and added to the socket error queue of the skb, if the skb has a socket associated with it.

The actual TX timestamp will reach userspace as a RX timestamp on the cloned packet. If timestamping is requested and no timestamping is done in the device driver (potentially this may use hardware timestamping), it will be done in software after the device's start_hard_xmit routine.

TODO: add SO_TIMESTAMPING define also to other platforms

---
 Documentation/networking/timestamping.txt          |  178 ++++++++
 Documentation/networking/timestamping/.gitignore   |    1 +
 Documentation/networking/timestamping/Makefile     |    3 +
 .../networking/timestamping/timestamping.c         |  469 ++++++++++++++++++++
 arch/x86/include/asm/socket.h                      |    3 +
 include/linux/errqueue.h                           |    1 +
 include/linux/net_tstamp.h                         |  104 +++++
 include/linux/sockios.h                            |    3 +
 8 files changed, 762 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/networking/timestamping.txt
 create mode 100644 Documentation/networking/timestamping/.gitignore
 create mode 100644 Documentation/networking/timestamping/Makefile
 create mode 100644 Documentation/networking/timestamping/timestamping.c
 create mode 100644 include/linux/net_tstamp.h
Documentation/networking/timestamping.txt new file +178 -0
new file mode 100644
index 0000000..a681a65
@@ -0,0 +1,178 @@
+The existing interfaces for getting network packages time stamped are:
+
+* SO_TIMESTAMP
+  Generate time stamp for each incoming packet using the (not necessarily
+  monotonous!) system time. Result is returned via recv_msg() in a
+  control message as timeval (usec resolution).
+
+* SO_TIMESTAMPNS
+  Same time stamping mechanism as SO_TIMESTAMP, but returns result as
+  timespec (nsec resolution).
+
+* IP_MULTICAST_LOOP + SO_TIMESTAMP[NS]
+  Only for multicasts: approximate send time stamp by receiving the looped
+  packet and using its receive time stamp.
+
+The following interface complements the existing ones: receive time
+stamps can be generated and returned for arbitrary packets and much
+closer to the point where the packet is really sent. Time stamps can
+be generated in software (as before) or in hardware (if the hardware
+has such a feature).
+
+SO_TIMESTAMPING:
+
+Instructs the socket layer which kind of information is wanted. The
+parameter is an integer with some of the following bits set. Setting
+other bits is an error and doesn't change the current state.
+
+SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamp in hardware
+SOF_TIMESTAMPING_TX_SOFTWARE:  if SOF_TIMESTAMPING_TX_HARDWARE is off or
+                               fails, then do it in software
+SOF_TIMESTAMPING_RX_HARDWARE:  return the original, unmodified time stamp
+                               as generated by the hardware
+SOF_TIMESTAMPING_RX_SOFTWARE:  if SOF_TIMESTAMPING_RX_HARDWARE is off or
+                               fails, then do it in software
+SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp
+SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to
+                               the system time base
+SOF_TIMESTAMPING_SOFTWARE:     return system time stamp generated in
+                               software
+
+SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
+SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
+following control message:
+    struct scm_timestamping {
+           struct timespec systime;
+           struct timespec hwtimetrans;
+           struct timespec hwtimeraw;
+    };
+
+recvmsg() can be used to get this control message for regular incoming
+packets. For send time stamps the outgoing packet is looped back to
+the socket's error queue with the send time stamp(s) attached. It can
+be received with recvmsg(flags=MSG_ERRQUEUE). The call returns the
+original outgoing packet data including all headers preprended down to
+and including the link layer, the scm_timestamping control message and
+a sock_extended_err control message with ee_errno==ENOMSG and
+ee_origin==SO_EE_ORIGIN_TIMESTAMPING. A socket with such a pending
+bounced packet is ready for reading as far as select() is concerned.
+
+All three values correspond to the same event in time, but were
+generated in different ways. Each of these values may be empty (= all
+zero), in which case no such value was available. If the application
+is not interested in some of these values, they can be left blank to
+avoid the potential overhead of calculating them.
+
+systime is the value of the system time at that moment. This
+corresponds to the value also returned via SO_TIMESTAMP[NS]. If the
+time stamp was generated by hardware, then this field is
+empty. Otherwise it is filled in if SOF_TIMESTAMPING_SOFTWARE is
+set.
+
+hwtimeraw is the original hardware time stamp. Filled in if
+SOF_TIMESTAMPING_RAW_HARDWARE is set. No assumptions about its
+relation to system time should be made.
+
+hwtimetrans is the hardware time stamp transformed so that it
+corresponds as good as possible to system time. This correlation is
+not perfect; as a consequence, sorting packets received via different
+NICs by their hwtimetrans may differ from the order in which they were
+received. hwtimetrans may be non-monotonic even for the same NIC.
+Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support
+by the network device and will be empty without that support.
+
+
+SIOCSHWTSTAMP:
+
+Hardware time stamping must also be initialized for each device driver
+that is expected to do hardware time stamping. The parameter is:
+
+struct hwtstamp_config {
+    int flags;           /* no flags defined right now, must be zero */
+    int tx_type;         /* HWTSTAMP_TX_* */
+    int rx_filter;       /* HWTSTAMP_FILTER_* */
+};
+
+Desired behavior is passed into the kernel and to a specific device by
+calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose
+ifr_data points to a struct hwtstamp_config. The tx_type and
+rx_filter are hints to the driver what it is expected to do. If
+the requested fine-grained filtering for incoming packets is not
+supported, the driver may time stamp more than just the requested types
+of packets.
+
+A driver which supports hardware time stamping shall update the struct
+with the actual, possibly more permissive configuration. If the
+requested packets cannot be time stamped, then nothing should be
+changed and ERANGE shall be returned (in contrast to EINVAL, which
+indicates that SIOCSHWTSTAMP is not supported at all).
+
+Only a processes with admin rights may change the configuration. User
+space is responsible to ensure that multiple processes don't interfere
+with each other and that the settings are reset.
+
+/* possible values for hwtstamp_config->tx_type */
+enum {
+	/*
+	 * no outgoing packet will need hardware time stamping;
+	 * should a packet arrive which asks for it, no hardware
+	 * time stamping will be done
+	 */
+	HWTSTAMP_TX_OFF,
+
+	/*
+	 * enables hardware time stamping for outgoing packets;
+	 * the sender of the packet decides which are to be
+	 * time stamped by setting SOF_TIMESTAMPING_TX_SOFTWARE
+	 * before sending the packet
+	 */
+	HWTSTAMP_TX_ON,
+};
+
+/* possible values for hwtstamp_config->rx_filter */
+enum {
+	/* time stamp no incoming packet at all */
+	HWTSTAMP_FILTER_NONE,
+
+	/* time stamp any incoming packet */
+	HWTSTAMP_FILTER_ALL,
+
+        /* return value: time stamp all packets requested plus some others */
+        HWTSTAMP_FILTER_SOME,
+
+	/* PTP v1, UDP, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
+
+        ...
+};
+
+
+DEVICE IMPLEMENTATION
+
+A driver which supports hardware time stamping must support the
+SIOCSHWTSTAMP ioctl. Time stamps for received packets must be stored
+in the skb with skb_hwtstamp_set().
+
+Time stamps for outgoing packets are to be generated as follows:
+- In hard_start_xmit(), check if skb_hwtstamp_check_tx_hardware()
+  returns non-zero. If yes, then the driver is expected
+  to do hardware time stamping.
+- If this is possible for the skb and requested, then declare
+  that the driver is doing the time stamping by calling
+  skb_hwtstamp_tx_in_progress(). A driver not supporting
+  hardware time stamping doesn't do that. A driver must never
+  touch sk_buff::tstamp! It is used to store how time stamping
+  for an outgoing packets is to be done.
+- As soon as the driver has sent the packet and/or obtained a
+  hardware time stamp for it, it passes the time stamp back by
+  calling skb_hwtstamp_tx() with the original skb, the raw
+  hardware time stamp and a handle to the device (necessary
+  to convert the hardware time stamp to system time). If obtaining
+  the hardware time stamp somehow fails, then the driver should
+  not fall back to software time stamping. The rationale is that
+  this would occur at a later time in the processing pipeline
+  than other software time stamping and therefore could lead
+  to unexpected deltas between time stamps.
+- If the driver did not call skb_hwtstamp_tx_in_progress(), then
+  dev_hard_start_xmit() checks whether software time stamping
+  is wanted as fallback and potentially generates the time stamp.
Documentation/networking/timestamping/.gitignore new file +1 -0
new file mode 100644
index 0000000..71e81eb
@@ -0,0 +1 @@
+timestamping
Documentation/networking/timestamping/Makefile new file +3 -0
new file mode 100644
index 0000000..ce170d1
@@ -0,0 +1,3 @@
+CPPFLAGS = -I../../../include
+
+timestamping: timestamping.c
Documentation/networking/timestamping/timestamping.c new file +469 -0

469 lines not on this page · raw message

arch/x86/include/asm/socket.h +3 -0
index 8ab9cc8..79e1f6c 100644
@@ -54,4 +54,7 @@
 
 #define SO_MARK			36
 
+#define SO_TIMESTAMPING         37
+#define SCM_TIMESTAMPING        SO_TIMESTAMPING
+
 #endif /* _ASM_X86_SOCKET_H */
include/linux/errqueue.h +1 -0
index 92f8d4f..86d88dd 100644
@@ -16,6 +16,7 @@ struct sock_extended_err
 #define SO_EE_ORIGIN_LOCAL	1
 #define SO_EE_ORIGIN_ICMP	2
 #define SO_EE_ORIGIN_ICMP6	3
+#define SO_EE_ORIGIN_TIMESTAMPING 4
 
 #define SO_EE_OFFENDER(ee)	((struct sockaddr*)((ee)+1))
 
include/linux/net_tstamp.h new file +104 -0

104 lines not on this page · raw message

include/linux/sockios.h +3 -0
index abef759..241f179 100644
@@ -122,6 +122,9 @@
 #define SIOCBRADDIF	0x89a2		/* add interface to bridge      */
 #define SIOCBRDELIF	0x89a3		/* remove interface from bridge */
 
+/* hardware time stamping: parameters in linux/net_tstamp.h */
+#define SIOCSHWTSTAMP   0x89b0
+
 /* Device private ioctl calls */
 
 /*
Signature · 1 line
1.5.5.3
#2 lore raw

RFC PATCH 2/12 net: infrastructure for hardware time stamping

Instead of adding new members to struct sk_buff this patch introduces and uses a generic mechanism for extending skb: additional structures are allocated at the end of the data area, similar to the skb_shared_info. One new member of skb holds the information which of the optional structures are present, with one bit per structure. This allows fast checks whether certain information is present.

The actual address of an optional structure
is found by using a hard-coded ordering of these structures and adding up the size and alignment padding of the preceeding structs.

The new struct skb_shared_tx is used to transport time stamping instructions to the device driver (outgoing packets). The resulting hardware time stamps are returned via struct skb_shared_hwtstamps (incoming or sent packets), in all formats possibly needed by the rest of the kernel and user space (original raw hardware time stamp and converted to system time base). This replaces the problematic callbacks into the network driver used in earlier revisions of this patch.

Conceptionally the two structs are independent and use different bits in the new flags fields. This avoids the problem that dev_start_hard_xmit() cannot distinguish reliably between outgoing and incoming packets (it is called for looped multicast packets). But to avoid copying sent data, the space reserved for skb_shared_tx is increased so that this space can be reused for skb_shared_hwtstamps when sending back the packet to the originating socket.

TX time stamping is implemented in software if the device driver doesn't support hardware time stamping.

The new semantic for hardware/software time stamping around net_device->hard_start_xmit() is based on two assumptions about existing network device drivers which don't support hardware time stamping and know nothing about it:
- they leave the new skb_shared_tx struct unmodified
- the keep the connection to the originating socket in skb->sk alive, i.e., don't call skb_orphan()

Given that skb_shared_tx is new, the first assumption is safe. The second is only true for some drivers. As a result, software TX time stamping currently works with the bnx2 driver, but not with the unmodified igb driver (the two drivers this patch series was tested with).

---
 include/linux/skbuff.h |  196 ++++++++++++++++++++++++++++++++++++++++++++++--
 net/core/dev.c         |   34 ++++++++-
 net/core/skbuff.c      |  139 ++++++++++++++++++++++++++++------
 3 files changed, 338 insertions(+), 31 deletions(-)
include/linux/skbuff.h +189 -7
index acf17af..7f58b55 100644
@@ -156,6 +156,105 @@ struct skb_shared_info {
 #endif
 };
 
+#define HAVE_HW_TIME_STAMP
+
+/**
+ * skb_shared_hwtstamps - optional hardware time stamps
+ *
+ * @hwtstamp:	hardware time stamp transformed into duration
+ *		since arbitrary point in time
+ * @syststamp:	hwtstamp transformed to system time base
+ *
+ * Software time stamps generated by ktime_get_real() are stored in
+ * skb->tstamp. The relation between the different kinds of time
+ * stamps is as follows:
+ *
+ * syststamp and tstamp can be compared against each other in
+ * arbitrary combinations.  The accuracy of a
+ * syststamp/tstamp/"syststamp from other device" comparison is
+ * limited by the accuracy of the transformation into system time
+ * base. This depends on the device driver and its underlying
+ * hardware.
+ *
+ * hwtstamps can only be compared against other hwtstamps from
+ * the same device.
+ *
+ * This additional structure has to be allocated together with
+ * the data buffer and is shared between clones.
+ */
+struct skb_shared_hwtstamps {
+	ktime_t	hwtstamp;
+	ktime_t	syststamp;
+};
+
+/**
+ * skb_shared_tx - optional instructions for time stamping of outgoing packets
+ *
+ * @hardware:		generate hardware time stamp
+ * @software:		generate software time stamp
+ * @in_progress:	device driver is going to provide
+ *			hardware time stamp
+ *
+ * This additional structure has to be allocated together with the
+ * data buffer and is shared between clones. Its space is reused
+ * in skb_tstamp_tx() for skb_shared_hwtstamps and therefore it
+ * has to be larger than strictly necessary (handled in skbuff.c).
+ */
+union skb_shared_tx {
+	struct {
+		__u8	hardware:1,
+			software:1,
+			in_progress:1;
+	};
+	__u8 flags;
+};
+
+/*
+ * Flags which control how &struct sk_buff is to be/was allocated.
+ * The &struct skb_shared_info always comes at sk_buff->end, then
+ * all of the optional structs in the order defined by their
+ * flags. Each structure is aligned so that it is at a multiple
+ * of its own size. Putting structs with less strict alignment
+ * requirements at the end increases the chance that no padding
+ * is needed.
+ *
+ * SKB_FLAGS_TXTSTAMP could be combined with SKB_FLAGS_HWTSTAMPS
+ * (outgoing packets have &union skb_shared_tx, incoming
+ * &struct skb_shared_hwtstamps), but telling apart one from
+ * the other is ambiguous: when a multicast packet is looped back,
+ * it has to be considered incoming, but it then passes through
+ * dev_hard_start_xmit() once more. Better avoid such ambiguities,
+ * in particular as it doesn't save any space. One additional byte
+ * is needed in any case.
+ *
+ * SKB_FLAGS_CLONE replaces the true/false integer fclone parameter in
+ * __alloc_skb(). Clones are marked as before in sk_buff->cloned.
+ *
+ * Similarly, SKB_FLAGS_NOBLOCK is used in place of a special noblock
+ * parameter in sock_alloc_send_skb().
+ *
+ * When adding optional structs, remember to update skb_optional_sizes
+ * in skbuff.c!
+ */
+enum {
+	/*
+	 * one byte holds the lower order flags in struct sk_buff,
+	 * so we could add more structs without additional costs
+	 */
+	SKB_FLAGS_OPTIONAL_HWTSTAMPS = 1 << 0,
+	SKB_FLAGS_OPTIONAL_TX = 1 << 1,
+
+	/* number of bits used for optional structures */
+	SKB_FLAGS_OPTIONAL_NUM = 2,
+
+	/*
+	 * the following flags only affect how the skb is allocated,
+	 * they are not stored like the ones above
+	 */
+	SKB_FLAGS_CLONE = 1 << 8,
+	SKB_FLAGS_NOBLOCK = 1 << 9,
+};
+
 /* We divide dataref into two halves.  The higher 16 bits hold references
  * to the payload part of skb->data.  The lower 16 bits hold references to
  * the entire skb->data.  A clone of a headerless skb holds the length of
@@ -228,6 +327,8 @@ typedef unsigned char *sk_buff_data_t;
  *	@ip_summed: Driver fed us an IP checksum
  *	@priority: Packet queueing priority
  *	@users: User count - see {datagram,tcp}.c
+ *	@optional: a combination of SKB_FLAGS_OPTIONAL_* flags, indicates
+ *		which of the corresponding structs were allocated
  *	@protocol: Packet protocol from driver
  *	@truesize: Buffer size 
  *	@head: Head of buffer
@@ -305,6 +406,8 @@ struct sk_buff {
 				ipvs_property:1,
 				peeked:1,
 				nf_trace:1;
+	/* not all of the bits in optional are used */
+	__u8			optional;
 	__be16			protocol;
 
 	void			(*destructor)(struct sk_buff *skb);
@@ -374,18 +477,18 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
 
 extern void kfree_skb(struct sk_buff *skb);
 extern void	       __kfree_skb(struct sk_buff *skb);
-extern struct sk_buff *__alloc_skb(unsigned int size,
-				   gfp_t priority, int fclone, int node);
+extern struct sk_buff *__alloc_skb_flags(unsigned int size,
+					gfp_t priority, int flags, int node);
 static inline struct sk_buff *alloc_skb(unsigned int size,
 					gfp_t priority)
 {
-	return __alloc_skb(size, priority, 0, -1);
+	return __alloc_skb_flags(size, priority, 0, -1);
 }
 
 static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
 					       gfp_t priority)
 {
-	return __alloc_skb(size, priority, 1, -1);
+	return __alloc_skb_flags(size, priority, SKB_FLAGS_CLONE, -1);
 }
 
 extern int skb_recycle_check(struct sk_buff *skb, int skb_size);
@@ -469,6 +572,29 @@ static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 #define skb_shinfo(SKB)	((struct skb_shared_info *)(skb_end_pointer(SKB)))
 
 /**
+ * __skb_get_optional - returns pointer to the requested structure
+ *
+ * @optional:	one of the SKB_FLAGS_OPTIONAL_* constants
+ *
+ * The caller must check that the structure is actually in the skb.
+ */
+extern void *__skb_get_optional(struct sk_buff *skb, int optional);
+
+static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
+{
+	return (skb->optional & SKB_FLAGS_OPTIONAL_HWTSTAMPS) ?
+		__skb_get_optional(skb, SKB_FLAGS_OPTIONAL_HWTSTAMPS) :
+		NULL;
+}
+
+static inline union skb_shared_tx *skb_tx(struct sk_buff *skb)
+{
+	return (skb->optional & SKB_FLAGS_OPTIONAL_TX) ?
+		__skb_get_optional(skb, SKB_FLAGS_OPTIONAL_TX) :
+		NULL;
+}
+
+/**
  *	skb_queue_empty - check if a queue is empty
  *	@list: queue head
  *
@@ -1399,8 +1525,33 @@ static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
 
 extern struct sk_buff *dev_alloc_skb(unsigned int length);
 
-extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
-		unsigned int length, gfp_t gfp_mask);
+/**
+ *	__netdev_alloc_skb_internal - allocate an skbuff for rx on a specific device
+ *	@dev: network device to receive on
+ *	@length: length to allocate
+ *	@flags: SKB_FLAGS_* mask
+ *	@gfp_mask: get_free_pages mask, passed to alloc_skb
+ *
+ *	Allocate a new &sk_buff and assign it a usage count of one. The
+ *	buffer has unspecified headroom built in. Users should allocate
+ *	the headroom they think they need without accounting for the
+ *	built in space. The built in space is used for optimisations.
+ *
+ *	%NULL is returned if there is no free memory.
+ *
+ *	This function takes the full set of parameters. There are aliases
+ *	with a smaller number of parameters.
+ */
+extern struct sk_buff *__netdev_alloc_skb_internal(struct net_device *dev,
+						unsigned int length, int flags,
+						gfp_t gfp_mask);
+
+static inline struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
+						unsigned int length,
+						gfp_t gfp_mask)
+{
+	return __netdev_alloc_skb_internal(dev, length, 0, gfp_mask);
+}
 
 /**
  *	netdev_alloc_skb - allocate an skbuff for rx on a specific device
@@ -1418,7 +1569,12 @@ extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
 static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
 		unsigned int length)
 {
-	return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
+	return __netdev_alloc_skb_internal(dev, length, 0, GFP_ATOMIC);
+}
+static inline struct sk_buff *netdev_alloc_skb_flags(struct net_device *dev,
+						unsigned int length, int flags)
+{
+	return __netdev_alloc_skb_internal(dev, length, flags, GFP_ATOMIC);
 }
 
 extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask);
@@ -1733,6 +1889,11 @@ static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
 
 extern void skb_init(void);
 
+static inline ktime_t skb_get_ktime(const struct sk_buff *skb)
+{
+	return skb->tstamp;
+}
+
 /**
  *	skb_get_timestamp - get timestamp from a skb
  *	@skb: skb to get stamp from
@@ -1747,6 +1908,11 @@ static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *
 	*stamp = ktime_to_timeval(skb->tstamp);
 }
 
+static inline void skb_get_timestampns(const struct sk_buff *skb, struct timespec *stamp)
+{
+	*stamp = ktime_to_timespec(skb->tstamp);
+}
+
 static inline void __net_timestamp(struct sk_buff *skb)
 {
 	skb->tstamp = ktime_get_real();
@@ -1762,6 +1928,22 @@ static inline ktime_t net_invalid_timestamp(void)
 	return ktime_set(0, 0);
 }
 
+/**
+ * skb_tstamp_tx - queue clone of skb with send time stamps
+ * @orig_skb:	the original outgoing packet
+ * @hwtstamps:	hardware time stamps, may be NULL if not available
+ *
+ * If the skb has a socket associated, then this function clones the
+ * skb (thus sharing the actual data and optional structures), stores
+ * the optional hardware time stamping information (if non NULL) or
+ * generates a software time stamp (otherwise), then queues the clone
+ * to the error queue of the socket.  Errors are silently ignored.
+ *
+ * May only be called on skbs which have a skb_shared_tx!
+ */
+extern void skb_tstamp_tx(struct sk_buff *orig_skb,
+			struct skb_shared_hwtstamps *hwtstamps);
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
net/core/dev.c +32 -2
index f54cac7..94d95a8 100644
@@ -1657,12 +1657,25 @@ static int dev_gso_segment(struct sk_buff *skb)
 	return 0;
 }
 
+static void tstamp_tx(struct sk_buff *skb)
+{
+	union skb_shared_tx *shtx =
+		skb_tx(skb);
+	if (unlikely(shtx &&
+			shtx->software &&
+			!shtx->in_progress)) {
+		skb_tstamp_tx(skb, NULL);
+	}
+}
+
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 			struct netdev_queue *txq)
 {
 	const struct net_device_ops *ops = dev->netdev_ops;
+	int rc;
 
 	prefetch(&dev->netdev_ops->ndo_start_xmit);
+
 	if (likely(!skb->next)) {
 		if (!list_empty(&ptype_all))
 			dev_queue_xmit_nit(skb, dev);
@@ -1674,13 +1687,29 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 				goto gso;
 		}
 
-		return ops->ndo_start_xmit(skb, dev);
+		rc = ops->ndo_start_xmit(skb, dev);
+		/*
+		 * TODO: if skb_orphan() was called by
+		 * dev->hard_start_xmit() (for example, the unmodified
+		 * igb driver does that; bnx2 doesn't), then
+		 * skb_tx_software_timestamp() will be unable to send
+		 * back the time stamp.
+		 *
+		 * How can this be prevented? Always create another
+		 * reference to the socket before calling
+		 * dev->hard_start_xmit()? Prevent that skb_orphan()
+		 * does anything in dev->hard_start_xmit() by clearing
+		 * the skb destructor before the call and restoring it
+		 * afterwards, then doing the skb_orphan() ourselves?
+		 */
+		if (likely(!rc))
+			tstamp_tx(skb);
+		return rc;
 	}
 
 gso:
 	do {
 		struct sk_buff *nskb = skb->next;
-		int rc;
 
 		skb->next = nskb->next;
 		nskb->next = NULL;
@@ -1690,6 +1719,7 @@ gso:
 			skb->next = nskb;
 			return rc;
 		}
+		tstamp_tx(skb);
 		if (unlikely(netif_tx_queue_stopped(txq) && skb->next))
 			return NETDEV_TX_BUSY;
 	} while (skb->next);
net/core/skbuff.c +117 -22

210 lines not on this page · raw message

Signature · 1 line
1.5.5.3
#3 lore raw

RFC PATCH 3/12 net: socket infrastructure for SO_TIMESTAMPING

The overlap with the old SO_TIMESTAMP[NS] options is handled so that time stamping in software (net_enable_timestamp()) is enabled when SO_TIMESTAMP[NS] and/or SO_TIMESTAMPING_RX_SOFTWARE is set. It's disabled if all of these are off.

---
 include/net/sock.h |   40 ++++++++++++++++++++++--
 net/compat.c       |   19 +++++++----
 net/core/sock.c    |   79 ++++++++++++++++++++++++++++++++++++++++-------
 net/socket.c       |   86 ++++++++++++++++++++++++++++++++++++++++------------
 4 files changed, 182 insertions(+), 42 deletions(-)
include/net/sock.h +37 -3
index 5a3a151..36807e4 100644
@@ -158,7 +158,7 @@ struct sock_common {
   *	@sk_allocation: allocation mode
   *	@sk_sndbuf: size of send buffer in bytes
   *	@sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
-  *		   %SO_OOBINLINE settings
+  *		   %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
   *	@sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
   *	@sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
   *	@sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
@@ -488,6 +488,13 @@ enum sock_flags {
 	SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */
 	SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */
 	SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */
+	SOCK_TIMESTAMPING_TX_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_TX_HARDWARE */
+	SOCK_TIMESTAMPING_TX_SOFTWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_TX_SOFTWARE */
+	SOCK_TIMESTAMPING_RX_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_RX_HARDWARE */
+	SOCK_TIMESTAMPING_RX_SOFTWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_RX_SOFTWARE */
+	SOCK_TIMESTAMPING_SOFTWARE,    /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_SOFTWARE */
+	SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_RAW_HARDWARE */
+	SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_SYS_HARDWARE */
 };
 
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1342,13 +1349,40 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
 	ktime_t kt = skb->tstamp;
 
-	if (sock_flag(sk, SOCK_RCVTSTAMP))
+	/*
+	 * generate control messages if
+	 * - receive time stamping in software requested (SOCK_RCVTSTAMP
+	 *   or SOCK_TIMESTAMPING_RX_SOFTWARE)
+	 * - software time stamp available and wanted (SOCK_TIMESTAMPING_SOFTWARE)
+	 * - hardware time stamps available and wanted (SOCK_TIMESTAMPING_SYS_HARDWARE
+	 *   or SOCK_TIMESTAMPING_RAW_HARDWARE)
+	 */
+	if (sock_flag(sk, SOCK_RCVTSTAMP) ||
+		sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) ||
+		(kt.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) ||
+		((skb->optional & SKB_FLAGS_OPTIONAL_HWTSTAMPS) &&
+			(sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) ||
+				sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE))))
 		__sock_recv_timestamp(msg, sk, skb);
 	else
 		sk->sk_stamp = kt;
 }
 
 /**
+ * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
+ * @msg:	outgoing packet
+ * @sk:		socket sending this packet
+ * @shtx:	filled with instructions for time stamping
+ *
+ * Currently only depends on SOCK_TIMESTAMPING* flags. Returns error code if
+ * parameters are invalid.
+ */
+extern int sock_tx_timestamp(struct msghdr *msg,
+			struct sock *sk,
+			union skb_shared_tx *shtx);
+
+
+/**
  * sk_eat_skb - Release a skb if it is no longer needed
  * @sk: socket to eat this skb from
  * @skb: socket buffer to eat
@@ -1416,7 +1450,7 @@ static inline struct sock *skb_steal_sock(struct sk_buff *skb)
 	return NULL;
 }
 
-extern void sock_enable_timestamp(struct sock *sk);
+extern void sock_enable_timestamp(struct sock *sk, int flag);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
 extern int sock_get_timestampns(struct sock *, struct timespec __user *);
 
net/compat.c +12 -7
index a3a2ba0..fb01ed9 100644
@@ -216,7 +216,7 @@ Efault:
 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
 {
 	struct compat_timeval ctv;
-	struct compat_timespec cts;
+	struct compat_timespec cts[3];
 	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 	struct compat_cmsghdr cmhdr;
 	int cmlen;
@@ -233,12 +233,17 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
 		data = &ctv;
 		len = sizeof(ctv);
 	}
-	if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS) {
+	if (level == SOL_SOCKET &&
+		(type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
+		int count = type == SCM_TIMESTAMPNS ? 1 : 3;
+		int i;
 		struct timespec *ts = (struct timespec *)data;
-		cts.tv_sec = ts->tv_sec;
-		cts.tv_nsec = ts->tv_nsec;
+		for (i = 0; i < count; i++) {
+			cts[i].tv_sec = ts[i].tv_sec;
+			cts[i].tv_nsec = ts[i].tv_nsec;
+		}
 		data = &cts;
-		len = sizeof(cts);
+		len = sizeof(cts[0]) * count;
 	}
 
 	cmlen = CMSG_COMPAT_LEN(len);
@@ -455,7 +460,7 @@ int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 	struct timeval tv;
 
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
-		sock_enable_timestamp(sk);
+		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
 	tv = ktime_to_timeval(sk->sk_stamp);
 	if (tv.tv_sec == -1)
 		return err;
@@ -479,7 +484,7 @@ int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *usersta
 	struct timespec ts;
 
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
-		sock_enable_timestamp(sk);
+		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
 	ts = ktime_to_timespec(sk->sk_stamp);
 	if (ts.tv_sec == -1)
 		return err;
net/core/sock.c +67 -12

135 lines not on this page · raw message

net/socket.c +66 -20

105 lines not on this page · raw message

Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#4 lore raw

RFC PATCH 4/12 sockets: allow allocating skb with optional structures

The internal sock_alloc_send_pskb() is now exposed as sock_alloc_send_skb_flags() and takes a flags parameter with additional instructions for how the skb is to be allocated. This is necessary for adding send time stamping information to outgoing packets.

sock_alloc_send_skb() is turned into a simple wrapper which preserves compatibility with code that passes a boolean "nblock" instead of the flags bitmask.

sock_alloc_send_pskb() was never called with non-zero data_len, therefore the obsolete code and parameter were removed.

---
 include/net/sock.h |   17 +++++++++++++----
 net/core/sock.c    |   50 +++++++-------------------------------------------
 2 files changed, 20 insertions(+), 47 deletions(-)
include/net/sock.h +13 -4
index 36807e4..6cb120c 100644
@@ -948,10 +948,19 @@ extern int			sock_setsockopt(struct socket *sock, int level,
 extern int			sock_getsockopt(struct socket *sock, int level,
 						int op, char __user *optval, 
 						int __user *optlen);
-extern struct sk_buff 		*sock_alloc_send_skb(struct sock *sk,
-						     unsigned long size,
-						     int noblock,
-						     int *errcode);
+extern struct sk_buff		*sock_alloc_send_skb_flags(struct sock *sk,
+						unsigned long size,
+						int flags,
+						int *errcode);
+inline static struct sk_buff 	*sock_alloc_send_skb(struct sock *sk,
+						unsigned long size,
+						int noblock,
+						int *errcode)
+{
+	return sock_alloc_send_skb_flags(sk, size,
+					noblock ? SKB_FLAGS_NOBLOCK : 0,
+					errcode);
+}
 extern void *sock_kmalloc(struct sock *sk, int size,
 			  gfp_t priority);
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
net/core/sock.c +7 -43

82 lines not on this page · raw message

Signature · 1 line
1.5.5.3
#5 lore raw

RFC PATCH 5/12 ip: support for TX timestamps on UDP and RAW sockets

Instructions for time stamping outgoing packets are take from the socket layer and later copied into the new skb.

---
 Documentation/networking/timestamping.txt |    2 ++
 include/net/ip.h                          |    1 +
 net/can/raw.c                             |   14 +++++++++++---
 net/ipv4/icmp.c                           |    2 ++
 net/ipv4/ip_output.c                      |   12 ++++++++++--
 net/ipv4/raw.c                            |    1 +
 net/ipv4/udp.c                            |    4 ++++
 7 files changed, 31 insertions(+), 5 deletions(-)
Documentation/networking/timestamping.txt +2 -0
index a681a65..0e58b45 100644
@@ -56,6 +56,8 @@ and including the link layer, the scm_timestamping control message and
 a sock_extended_err control message with ee_errno==ENOMSG and
 ee_origin==SO_EE_ORIGIN_TIMESTAMPING. A socket with such a pending
 bounced packet is ready for reading as far as select() is concerned.
+If the outgoing packet has to be fragmented, then only the first
+fragment is time stamped and returned to the sending socket.
 
 All three values correspond to the same event in time, but were
 generated in different ways. Each of these values may be empty (= all
include/net/ip.h +1 -0
index 1086813..4ac7577 100644
@@ -55,6 +55,7 @@ struct ipcm_cookie
 	__be32			addr;
 	int			oif;
 	struct ip_options	*opt;
+	union skb_shared_tx	shtx;
 };
 
 #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
net/can/raw.c +11 -3
index 27aab63..1f2111d 100644
@@ -618,6 +618,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 	struct raw_sock *ro = raw_sk(sk);
 	struct sk_buff *skb;
 	struct net_device *dev;
+	union skb_shared_tx shtx;
 	int ifindex;
 	int err;
 
@@ -639,8 +640,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 	if (!dev)
 		return -ENXIO;
 
-	skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
-				  &err);
+	err = sock_tx_timestamp(msg, sk, &shtx);
+	if (err < 0)
+		return err;
+
+	skb = sock_alloc_send_skb_flags(sk, size,
+				((msg->msg_flags & MSG_DONTWAIT) ? SKB_FLAGS_NOBLOCK : 0) |
+					(shtx.flags ? SKB_FLAGS_OPTIONAL_TX : 0),
+				&err);
 	if (!skb)
 		goto put_dev;
 
@@ -649,7 +656,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 		goto free_skb;
 	skb->dev = dev;
 	skb->sk  = sk;
-
+	if (shtx.flags)
+		*skb_tx(skb) = shtx;
 	err = can_send(skb, ro->loopback);
 
 	dev_put(dev);
net/ipv4/icmp.c +2 -0
index 705b33b..382800a 100644
@@ -375,6 +375,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 	inet->tos = ip_hdr(skb)->tos;
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 	if (icmp_param->replyopts.optlen) {
 		ipc.opt = &icmp_param->replyopts;
 		if (ipc.opt->srr)
@@ -532,6 +533,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 	inet_sk(sk)->tos = tos;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
+	ipc.shtx.flags = 0;
 
 	{
 		struct flowi fl = {
net/ipv4/ip_output.c +10 -2
index 8ebe86d..ed92f0b 100644
@@ -923,9 +923,11 @@ alloc_new_skb:
 				alloclen += rt->u.dst.trailer_len;
 
 			if (transhdrlen) {
-				skb = sock_alloc_send_skb(sk,
+				skb = sock_alloc_send_skb_flags(sk,
 						alloclen + hh_len + 15,
-						(flags & MSG_DONTWAIT), &err);
+				       		((flags & MSG_DONTWAIT) ? SKB_FLAGS_NOBLOCK : 0) |
+							(ipc->shtx.flags ? SKB_FLAGS_OPTIONAL_TX : 0),
+						&err);
 			} else {
 				skb = NULL;
 				if (atomic_read(&sk->sk_wmem_alloc) <=
@@ -935,6 +937,9 @@ alloc_new_skb:
 							   sk->sk_allocation);
 				if (unlikely(skb == NULL))
 					err = -ENOBUFS;
+				else
+					/* only the initial fragment is time stamped */
+					ipc->shtx.flags = 0;
 			}
 			if (skb == NULL)
 				goto error;
@@ -945,6 +950,8 @@ alloc_new_skb:
 			skb->ip_summed = csummode;
 			skb->csum = 0;
 			skb_reserve(skb, hh_len);
+			if (ipc->shtx.flags)
+				*skb_tx(skb) = ipc->shtx;
 
 			/*
 			 *	Find where to start putting bytes.
@@ -1364,6 +1371,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
 
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 
 	if (replyopts.opt.optlen) {
 		ipc.opt = &replyopts.opt;
net/ipv4/raw.c +1 -0
index dff8bc4..f774651 100644
@@ -493,6 +493,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
 	ipc.addr = inet->saddr;
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 	ipc.oif = sk->sk_bound_dev_if;
 
 	if (msg->msg_controllen) {
net/ipv4/udp.c +4 -0
index cf5ab05..bbf1a6d 100644
@@ -573,6 +573,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		return -EOPNOTSUPP;
 
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 
 	if (up->pending) {
 		/*
@@ -620,6 +621,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	ipc.addr = inet->saddr;
 
 	ipc.oif = sk->sk_bound_dev_if;
+	err = sock_tx_timestamp(msg, sk, &ipc.shtx);
+	if (err)
+		return err;
 	if (msg->msg_controllen) {
 		err = ip_cmsg_send(sock_net(sk), msg, &ipc);
 		if (err)
Signature · 1 line
1.5.5.3
#6 lore raw

RFC PATCH 6/12 debug: NULL pointer check in ip_output

---
 net/ipv4/ip_output.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)
net/ipv4/ip_output.c +8 -2
index ed92f0b..03a6706 100644
@@ -950,8 +950,14 @@ alloc_new_skb:
 			skb->ip_summed = csummode;
 			skb->csum = 0;
 			skb_reserve(skb, hh_len);
-			if (ipc->shtx.flags)
-				*skb_tx(skb) = ipc->shtx;
+			if (ipc->shtx.flags) {
+				if (skb_tx(skb)) 
+					*skb_tx(skb) = ipc->shtx;
+				else
+					printk(KERN_DEBUG
+						"ERROR: skb with flags %x and no tx ptr\n",
+						ipc->shtx.flags);
+			}
 
 			/*
 			 *	Find where to start putting bytes.
Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#7 lore raw

RFC PATCH 7/12 net: pass new SIOCSHWTSTAMP through to device drivers

---
 fs/compat_ioctl.c |    1 +
 net/core/dev.c    |    2 ++
 2 files changed, 3 insertions(+), 0 deletions(-)
fs/compat_ioctl.c +1 -0
index 5235c67..a5001a6 100644
@@ -2555,6 +2555,7 @@ HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc)
+HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc)
 
 /* ioctls used by appletalk ddp.c */
 HANDLE_IOCTL(SIOCATALKDIFADDR, dev_ifsioc)
net/core/dev.c +2 -0
index 94d95a8..dc7b4fc 100644
@@ -3675,6 +3675,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
 			    cmd == SIOCSMIIREG ||
 			    cmd == SIOCBRADDIF ||
 			    cmd == SIOCBRDELIF ||
+			    cmd == SIOCSHWTSTAMP ||
 			    cmd == SIOCWANDEV) {
 				err = -EOPNOTSUPP;
 				if (ops->ndo_do_ioctl) {
@@ -3829,6 +3830,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 		case SIOCBONDCHANGEACTIVE:
 		case SIOCBRADDIF:
 		case SIOCBRDELIF:
+		case SIOCSHWTSTAMP:
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			/* fall through */
Signature · 1 line
1.5.5.3
#8 lore raw

RFC PATCH 8/12 igb: stub support for SIOCSHWTSTAMP

---
 drivers/net/igb/igb_main.c |   30 ++++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)
drivers/net/igb/igb_main.c +30 -0
index 25df7c9..e9ad560 100644
@@ -34,6 +34,7 @@
 #include <linux/ipv6.h>
 #include <net/checksum.h>
 #include <net/ip6_checksum.h>
+#include <linux/net_tstamp.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
@@ -4121,6 +4122,33 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 }
 
 /**
+ * igb_hwtstamp_ioctl - control hardware time stamping
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ *
+ * Currently cannot enable any kind of hardware time stamping, but
+ * supports SIOCSHWTSTAMP in general.
+ **/
+static int igb_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct hwtstamp_config config;
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	/* reserved for future extensions */
+	if (config.flags)
+		return -EINVAL;
+
+	if (config.tx_type == HWTSTAMP_TX_OFF &&
+		config.rx_filter == HWTSTAMP_FILTER_NONE)
+		return 0;
+
+	return -ERANGE;
+}
+
+/**
  * igb_ioctl -
  * @netdev:
  * @ifreq:
@@ -4133,6 +4161,8 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 	case SIOCGMIIREG:
 	case SIOCSMIIREG:
 		return igb_mii_ioctl(netdev, ifr, cmd);
+	case SIOCSHWTSTAMP:
+		return igb_hwtstamp_ioctl(netdev, ifr, cmd);
 	default:
 		return -EOPNOTSUPP;
 	}
Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#9 lore raw

RFC PATCH 9/12 clocksource: allow usage independent of timekeeping.c

So far struct clocksource acted as the interface between time/timekeeping.c and hardware. This patch generalizes the concept so that a similar interface can also be used in other contexts. For that it introduces new structures and related functions *without* touching the existing struct clocksource.

The reasons for adding these new structures to clocksource.[ch] are
* the APIs are clearly related
* struct clocksource could be cleaned up to use the new structs
* avoids proliferation of files with similar names (timesource.h? timecounter.h?)

As outlined in the discussion with John Stultz, this patch adds
* struct cyclecounter: stateless API to hardware which counts clock cycles
* struct timecounter: stateful utility code built on a cyclecounter which provides a nanosecond counter
* only the function to read the nanosecond counter; deltas are used internally and not exposed to users of timecounter

The code does no locking of the shared state. It must be called at least as often as the cycle counter wraps around to detect these wrap arounds. Both is the responsibility of the timecounter user.

---
 include/linux/clocksource.h |   99 +++++++++++++++++++++++++++++++++++++++++++
 kernel/time/clocksource.c   |   76 +++++++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 0 deletions(-)
include/linux/clocksource.h +99 -0
index f88d32f..d379189 100644
@@ -22,8 +22,107 @@ typedef u64 cycle_t;
 struct clocksource;
 
 /**
+ * struct cyclecounter - hardware abstraction for a free running counter
+ *	Provides completely state-free accessors to the underlying hardware.
+ *	Depending on which hardware it reads, the cycle counter may wrap
+ *	around quickly. Locking rules (if necessary) have to be defined
+ *	by the implementor and user of specific instances of this API.
+ *
+ * @read:		returns the current cycle value
+ * @mask:		bitmask for two's complement
+ *			subtraction of non 64 bit counters,
+ *			see CLOCKSOURCE_MASK() helper macro
+ * @mult:		cycle to nanosecond multiplier
+ * @shift:		cycle to nanosecond divisor (power of two)
+ */
+struct cyclecounter {
+	cycle_t (*read)(const struct cyclecounter *cc);
+	cycle_t mask;
+	u32 mult;
+	u32 shift;
+};
+
+/**
+ * struct timecounter - layer above a %struct cyclecounter which counts nanoseconds
+ *	Contains the state needed by timecounter_read() to detect
+ *	cycle counter wrap around. Initialize with
+ *	timecounter_init(). Also used to convert cycle counts into the
+ *	corresponding nanosecond counts with timecounter_cyc2time(). Users
+ *	of this code are responsible for initializing the underlying
+ *	cycle counter hardware, locking issues and reading the time
+ *	more often than the cycle counter wraps around. The nanosecond
+ *	counter will only wrap around after ~585 years.
+ *
+ * @cc:			the cycle counter used by this instance
+ * @cycle_last:		most recent cycle counter value seen by timecounter_read()
+ * @nsec:		
+ */
+struct timecounter {
+	const struct cyclecounter *cc;
+	cycle_t cycle_last;
+	u64 nsec;
+};
+
+/**
+ * cyclecounter_cyc2ns - converts cycle counter cycles to nanoseconds
+ * @tc:		Pointer to cycle counter.
+ * @cycles:	Cycles
+ *
+ * XXX - This could use some mult_lxl_ll() asm optimization. Same code
+ * as in cyc2ns, but with unsigned result.
+ */
+static inline u64 cyclecounter_cyc2ns(const struct cyclecounter *cc, cycle_t cycles)
+{
+	u64 ret = (u64)cycles;
+	ret = (ret * cc->mult) >> cc->shift;
+	return ret;
+}
+
+/**
+ * timecounter_init - initialize a time counter
+ * @tc:			Pointer to time counter which is to be initialized/reset
+ * @cc:			A cycle counter, ready to be used.
+ * @start_tstamp:	Arbitrary initial time stamp.
+ *
+ * After this call the current cycle register (roughly) corresponds to
+ * the initial time stamp. Every call to timecounter_read() increments
+ * the time stamp counter by the number of elapsed nanoseconds.
+ */
+extern void timecounter_init(struct timecounter *tc,
+			const struct cyclecounter *cc,
+			u64 start_tstamp);
+
+/**
+ * timecounter_read - return nanoseconds elapsed since timecounter_init()
+ *                         plus the initial time stamp
+ * @tc:          Pointer to time counter.
+ *
+ * In other words, keeps track of time since the same epoch as
+ * the function which generated the initial time stamp.
+ */
+extern u64 timecounter_read(struct timecounter *tc);
+
+/**
+ * timecounter_cyc2time - convert a cycle counter to same
+ *                        time base as values returned by
+ *                        timecounter_read()
+ * @tc:		Pointer to time counter.
+ * @cycle:	a value returned by tc->cc->read()
+ *
+ * Cycle counts that are converted correctly as long as they
+ * fall into the interval [-1/2 max cycle count, +1/2 max cycle count],
+ * with "max cycle count" == cs->mask+1.
+ *
+ * This allows conversion of cycle counter values which were generated
+ * in the past.
+ */
+extern u64 timecounter_cyc2time(struct timecounter *tc,
+				cycle_t cycle_tstamp);
+
+/**
  * struct clocksource - hardware abstraction for a free running counter
  *	Provides mostly state-free accessors to the underlying hardware.
+ *	This is the structure used for system time.
  *
  * @name:		ptr to clocksource name
  * @list:		list head for registration
kernel/time/clocksource.c +76 -0

82 lines not on this page · raw message

Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#10 lore raw

RFC PATCH 10/12 igb: access to NIC time

Adds the register definitions and code to read the time register.

---
 drivers/net/igb/e1000_regs.h |   28 +++++++++++
 drivers/net/igb/igb.h        |    4 ++
 drivers/net/igb/igb_main.c   |  106 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 138 insertions(+), 0 deletions(-)
drivers/net/igb/e1000_regs.h +28 -0
index bdf5d83..d225601 100644
@@ -75,6 +75,34 @@
 #define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
 #define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
 #define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+
+/* IEEE 1588 TIMESYNCH */
+#define E1000_TSYNCTXCTL 0x0B614
+#define E1000_TSYNCRXCTL 0x0B620
+#define E1000_TSYNCRXCFG 0x05F50
+
+#define E1000_SYSTIML 0x0B600
+#define E1000_SYSTIMH 0x0B604
+#define E1000_TIMINCA 0x0B608
+
+#define E1000_RXMTRL     0x0B634
+#define E1000_RXSTMPL 0x0B624
+#define E1000_RXSTMPH 0x0B628
+#define E1000_RXSATRL 0x0B62C
+#define E1000_RXSATRH 0x0B630
+
+#define E1000_TXSTMPL 0x0B618
+#define E1000_TXSTMPH 0x0B61C
+
+#define E1000_ETQF0   0x05CB0
+#define E1000_ETQF1   0x05CB4
+#define E1000_ETQF2   0x05CB8
+#define E1000_ETQF3   0x05CBC
+#define E1000_ETQF4   0x05CC0
+#define E1000_ETQF5   0x05CC4
+#define E1000_ETQF6   0x05CC8
+#define E1000_ETQF7   0x05CCC
+
 /* Split and Replication RX Control - RW */
 /*
  * Convenience macros
drivers/net/igb/igb.h +4 -0
index 2121b8b..2db4c64 100644
@@ -34,6 +34,8 @@
 #include "e1000_mac.h"
 #include "e1000_82575.h"
 
+#include <linux/clocksource.h>
+
 struct igb_adapter;
 
 #ifdef CONFIG_IGB_LRO
@@ -262,6 +264,8 @@ struct igb_adapter {
 	struct napi_struct napi;
 	struct pci_dev *pdev;
 	struct net_device_stats net_stats;
+	struct cyclecounter cycles;
+	struct timecounter clock;
 
 	/* structs defined in e1000_hw.h */
 	struct e1000_hw hw;
drivers/net/igb/igb_main.c +106 -0

124 lines not on this page · raw message

Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#11 lore raw

RFC PATCH 11/12 time sync: generic infrastructure to map between time stamps generated by a time counter and system time

Currently only mapping from time counter to system time is implemented. The interface could have been made more versatile by not depending on a time counter, but this wasn't done to avoid writing glue code elsewhere.

The method implemented here is the one used and analyzed under the name "assisted PTP" in the LCI PTP paper:
http://www.linuxclustersinstitute.org/conferences/archive/2008/PDF/Ohly_92221.pdf

---
 include/linux/clocksync.h |   85 +++++++++++++++++++++
 kernel/time/Makefile      |    2 +-
 kernel/time/clocksync.c   |  182 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 268 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/clocksync.h
 create mode 100644 kernel/time/clocksync.c
include/linux/clocksync.h new file +85 -0
new file mode 100644
index 0000000..d2f93f8
@@ -0,0 +1,85 @@
+/*
+ * Utility code which helps transforming between hardware time stamps
+ * generated by a clocksource and system time. The clocksource is
+ * assumed to return monotonically increasing time (but this code does
+ * its best to compensate if that is not the case) whereas system time
+ * may jump.
+ */
+#ifndef _LINUX_CLOCKSYNC_H
+#define _LINUX_CLOCKSYNC_H
+
+#include <linux/clocksource.h>
+#include <linux/ktime.h>
+
+/**
+ * struct clocksync - stores state and configuration for the two clocks
+ *
+ * Initialize to zero, then set clock, systime, num_samples.
+ *
+ * Transformation between HW time and system time is done with:
+ * HW time transformed = HW time + offset +
+ *                       (HW time - last_update) * skew / CLOCKSYNC_SKEW_RESOLUTION
+ *
+ * @clock:           the source for HW time stamps (%clocksource_read_time)
+ * @systime:         function returning current system time (ktime_get
+ *                   for monotonic time, or ktime_get_real for wall clock)
+ * @num_samples:     number of times that HW time and system time are to
+ *                   be compared when determining their offset
+ * @offset:          (system time - HW time) at the time of the last update
+ * @skew:            average (system time - HW time) / delta HW time *
+ *                   CLOCKSYNC_SKEW_RESOLUTION
+ * @last_update:     last HW time stamp when clock offset was measured
+ */
+struct clocksync {
+	struct timecounter *clock;
+	ktime_t (*systime)(void);
+	int num_samples;
+
+	s64 offset;
+	s64 skew;
+	u64 last_update;
+};
+
+/**
+ * clocksync_hw2sys - transform HW time stamp into corresponding system time
+ * @sync:             context for clock sync
+ * @hwtstamp:         the result of timecounter_read() or
+ *                    timecounter_cyc2time()
+ */
+extern ktime_t clocksync_hw2sys(struct clocksync *sync,
+				u64 hwtstamp);
+
+/**
+ * clocksync_offset - measure current (system time - HW time) offset
+ * @sync:             context for clock sync
+ * @offset:           average offset during sample period returned here
+ * @hwtstamp:         average HW time during sample period returned here
+ *
+ * Returns number of samples used. Might be zero (= no result) in the
+ * unlikely case that system time was monotonically decreasing for all
+ * samples (= broken).
+ */
+extern int clocksync_offset(struct clocksync *sync,
+			s64 *offset,
+			u64 *hwtstamp);
+
+extern void __clocksync_update(struct clocksync *sync,
+			u64 hwtstamp);
+
+/**
+ * clocksync_update - update offset and skew by measuring current offset
+ * @sync:             context for clock sync
+ * @hwtstamp:         the result of timecounter_read() or
+ *                    timecounter_cyc2time(), pass zero to force update
+ *
+ * Updates are only done at most once per second.
+ */
+static inline void clocksync_update(struct clocksync *sync,
+			u64 hwtstamp)
+{
+	if (!hwtstamp ||
+		(s64)(hwtstamp - sync->last_update) >= NSEC_PER_SEC)
+		__clocksync_update(sync, hwtstamp);
+}
+
+#endif /* _LINUX_CLOCKSYNC_H */
kernel/time/Makefile +1 -1
index 905b0b5..6279fb0 100644
@@ -1,4 +1,4 @@
-obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
+obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o clocksync.o
 
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)		+= clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)		+= tick-common.o
kernel/time/clocksync.c new file +182 -0

182 lines not on this page · raw message

Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#12 lore raw

RFC PATCH 12/12 igb: use clocksync to implement hardware time stamping

Both TX and RX hardware time stamping are implemented. Due to hardware limitations it is not possible to verify reliably which packet was time stamped when multiple were pending for sending; this could be solved by only allowing one packet marked for hardware time stamping into the queue (not implemented yet).

RX time stamping relies on the flag in the packet descriptor which marks packets that were time stamped. In "all packet" mode this flag is not set. TODO: also support that mode (even though it'll suffer from race conditions).

Allocation of RX buffers is not optimal yet: the extra space for hardware time stamps is always allocated. Either this should only be done when HW time stamping is (implies reallocation of buffers) or packets with HW time stamps should be copied into a larger buffer (implies higher overhead for those packets).

---
 drivers/net/igb/e1000_82575.h   |    1 +
 drivers/net/igb/e1000_defines.h |    1 +
 drivers/net/igb/e1000_regs.h    |   40 ++++++
 drivers/net/igb/igb.h           |    4 +
 drivers/net/igb/igb_main.c      |  275 +++++++++++++++++++++++++++++++++++++--
 5 files changed, 312 insertions(+), 9 deletions(-)
drivers/net/igb/e1000_82575.h +1 -0
index c1928b5..dd32a6f 100644
@@ -116,6 +116,7 @@ union e1000_adv_tx_desc {
 };
 
 /* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_MAC_TSTAMP   0x00080000 /* IEEE1588 Timestamp packet */
 #define E1000_ADVTXD_DTYP_CTXT    0x00200000 /* Advanced Context Descriptor */
 #define E1000_ADVTXD_DTYP_DATA    0x00300000 /* Advanced Data Descriptor */
 #define E1000_ADVTXD_DCMD_IFCS    0x02000000 /* Insert FCS (Ethernet CRC) */
drivers/net/igb/e1000_defines.h +1 -0
index c5fe784..587f424 100644
@@ -104,6 +104,7 @@
 #define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
 #define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
 #define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_TS       0x10000 /* Pkt was time stamped */
 #define E1000_RXD_ERR_CE        0x01    /* CRC Error */
 #define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
 #define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
drivers/net/igb/e1000_regs.h +40 -0
index d225601..215d4d6 100644
@@ -78,9 +78,37 @@
 
 /* IEEE 1588 TIMESYNCH */
 #define E1000_TSYNCTXCTL 0x0B614
+#define E1000_TSYNCTXCTL_VALID (1<<0)
+#define E1000_TSYNCTXCTL_ENABLED (1<<4)
 #define E1000_TSYNCRXCTL 0x0B620
+#define E1000_TSYNCRXCTL_VALID (1<<0)
+#define E1000_TSYNCRXCTL_ENABLED (1<<4)
+enum {
+	E1000_TSYNCRXCTL_TYPE_L2_V2 = 0,
+	E1000_TSYNCRXCTL_TYPE_L4_V1 = (1<<1),
+	E1000_TSYNCRXCTL_TYPE_L2_L4_V2 = (1<<2),
+	E1000_TSYNCRXCTL_TYPE_ALL = (1<<3),
+	E1000_TSYNCRXCTL_TYPE_EVENT_V2 = (1<<3) | (1<<1),
+};
 #define E1000_TSYNCRXCFG 0x05F50
+enum {
+	E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE = 0<<0,
+	E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE = 1<<0,
+	E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE = 2<<0,
+	E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE = 3<<0,
+	E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE = 4<<0,
 
+	E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE = 0<<8,
+	E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE = 1<<8,
+	E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE = 2<<8,
+	E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE = 3<<8,
+	E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE = 8<<8,
+	E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE = 9<<8,
+	E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE = 0xA<<8,
+	E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE = 0xB<<8,
+	E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE = 0xC<<8,
+	E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE = 0xD<<8,
+};
 #define E1000_SYSTIML 0x0B600
 #define E1000_SYSTIMH 0x0B604
 #define E1000_TIMINCA 0x0B608
@@ -103,6 +131,18 @@
 #define E1000_ETQF6   0x05CC8
 #define E1000_ETQF7   0x05CCC
 
+/* Filtering Registers */
+#define E1000_SAQF(_n) (0x5980 + 4 * (_n))
+#define E1000_DAQF(_n) (0x59A0 + 4 * (_n))
+#define E1000_SPQF(_n) (0x59C0 + 4 * (_n))
+#define E1000_FTQF(_n) (0x59E0 + 4 * (_n))
+#define E1000_SAQF0 E1000_SAQF(0)
+#define E1000_DAQF0 E1000_DAQF(0)
+#define E1000_SPQF0 E1000_SPQF(0)
+#define E1000_FTQF0 E1000_FTQF(0)
+#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
+#define E1000_ETQF(_n)  (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
+
 /* Split and Replication RX Control - RW */
 /*
  * Convenience macros
drivers/net/igb/igb.h +4 -0
index 2db4c64..65863d0 100644
@@ -35,6 +35,8 @@
 #include "e1000_82575.h"
 
 #include <linux/clocksource.h>
+#include <linux/clocksync.h>
+#include <linux/net_tstamp.h>
 
 struct igb_adapter;
 
@@ -266,6 +268,8 @@ struct igb_adapter {
 	struct net_device_stats net_stats;
 	struct cyclecounter cycles;
 	struct timecounter clock;
+	struct clocksync sync;
+	struct hwtstamp_config hwtstamp_config;
 
 	/* structs defined in e1000_hw.h */
 	struct e1000_hw hw;
drivers/net/igb/igb_main.c +266 -9

359 lines not on this page · raw message

Signature · 1 line
1.5.5.3
Acked-by on v1 9/12
#13 lore raw

Re: [RFC PATCH 09/12] clocksource: allow usage independent of timekeeping.c

In reply to Patrick Ohly
Quoted 19 lines · Patrick Ohly

So far struct clocksource acted as the interface between time/timekeeping.c and hardware. This patch generalizes the concept so that a similar interface can also be used in other contexts. For that it introduces new structures and related functions *without* touching the existing struct clocksource.

The reasons for adding these new structures to clocksource.[ch] are
* the APIs are clearly related
* struct clocksource could be cleaned up to use the new structs
* avoids proliferation of files with similar names (timesource.h? timecounter.h?)

As outlined in the discussion with John Stultz, this patch adds
* struct cyclecounter: stateless API to hardware which counts clock cycles
* struct timecounter: stateful utility code built on a cyclecounter which provides a nanosecond counter
* only the function to read the nanosecond counter; deltas are used internally and not exposed to users of timecounter

Quoted 5 lines

The code does no locking of the shared state. It must be called at least as often as the cycle counter wraps around to detect these wrap arounds. Both is the responsibility of the timecounter user.

Nice. The cyclecounter struct can work as a good base that I can shift the clocksource bits over to as I clean that up.

We will probably want to split this out down the road, but for now its small enough and related enough that I think its fine in the clocksource.h/c.

Also since Magnus has been working on it, does enable/disable accessors in the cyclecounter struct make sense for your hardware as well?

Also the corner cases on overflows (how we manage the state, should reads be deferred for too long) will need to be addressed, but I guess we can solve that when it becomes an issue. Just to be clear: none of the hardware you're submitting this round has wrapping issues? Or is that not the case?

Otherwise,

thanks
-john

Quoted 194 lines
---
 include/linux/clocksource.h |   99 +++++++++++++++++++++++++++++++++++++++++++
 kernel/time/clocksource.c   |   76 +++++++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 0 deletions(-)
include/linux/clocksource.h +99 -0
index f88d32f..d379189 100644
@@ -22,8 +22,107 @@ typedef u64 cycle_t;
 struct clocksource;
 
 /**
+ * struct cyclecounter - hardware abstraction for a free running counter
+ *	Provides completely state-free accessors to the underlying hardware.
+ *	Depending on which hardware it reads, the cycle counter may wrap
+ *	around quickly. Locking rules (if necessary) have to be defined
+ *	by the implementor and user of specific instances of this API.
+ *
+ * @read:		returns the current cycle value
+ * @mask:		bitmask for two's complement
+ *			subtraction of non 64 bit counters,
+ *			see CLOCKSOURCE_MASK() helper macro
+ * @mult:		cycle to nanosecond multiplier
+ * @shift:		cycle to nanosecond divisor (power of two)
+ */
+struct cyclecounter {
+	cycle_t (*read)(const struct cyclecounter *cc);
+	cycle_t mask;
+	u32 mult;
+	u32 shift;
+};
+
+/**
+ * struct timecounter - layer above a %struct cyclecounter which counts nanoseconds
+ *	Contains the state needed by timecounter_read() to detect
+ *	cycle counter wrap around. Initialize with
+ *	timecounter_init(). Also used to convert cycle counts into the
+ *	corresponding nanosecond counts with timecounter_cyc2time(). Users
+ *	of this code are responsible for initializing the underlying
+ *	cycle counter hardware, locking issues and reading the time
+ *	more often than the cycle counter wraps around. The nanosecond
+ *	counter will only wrap around after ~585 years.
+ *
+ * @cc:			the cycle counter used by this instance
+ * @cycle_last:		most recent cycle counter value seen by timecounter_read()
+ * @nsec:		
+ */
+struct timecounter {
+	const struct cyclecounter *cc;
+	cycle_t cycle_last;
+	u64 nsec;
+};
+
+/**
+ * cyclecounter_cyc2ns - converts cycle counter cycles to nanoseconds
+ * @tc:		Pointer to cycle counter.
+ * @cycles:	Cycles
+ *
+ * XXX - This could use some mult_lxl_ll() asm optimization. Same code
+ * as in cyc2ns, but with unsigned result.
+ */
+static inline u64 cyclecounter_cyc2ns(const struct cyclecounter *cc, cycle_t cycles)
+{
+	u64 ret = (u64)cycles;
+	ret = (ret * cc->mult) >> cc->shift;
+	return ret;
+}
+
+/**
+ * timecounter_init - initialize a time counter
+ * @tc:			Pointer to time counter which is to be initialized/reset
+ * @cc:			A cycle counter, ready to be used.
+ * @start_tstamp:	Arbitrary initial time stamp.
+ *
+ * After this call the current cycle register (roughly) corresponds to
+ * the initial time stamp. Every call to timecounter_read() increments
+ * the time stamp counter by the number of elapsed nanoseconds.
+ */
+extern void timecounter_init(struct timecounter *tc,
+			const struct cyclecounter *cc,
+			u64 start_tstamp);
+
+/**
+ * timecounter_read - return nanoseconds elapsed since timecounter_init()
+ *                         plus the initial time stamp
+ * @tc:          Pointer to time counter.
+ *
+ * In other words, keeps track of time since the same epoch as
+ * the function which generated the initial time stamp.
+ */
+extern u64 timecounter_read(struct timecounter *tc);
+
+/**
+ * timecounter_cyc2time - convert a cycle counter to same
+ *                        time base as values returned by
+ *                        timecounter_read()
+ * @tc:		Pointer to time counter.
+ * @cycle:	a value returned by tc->cc->read()
+ *
+ * Cycle counts that are converted correctly as long as they
+ * fall into the interval [-1/2 max cycle count, +1/2 max cycle count],
+ * with "max cycle count" == cs->mask+1.
+ *
+ * This allows conversion of cycle counter values which were generated
+ * in the past.
+ */
+extern u64 timecounter_cyc2time(struct timecounter *tc,
+				cycle_t cycle_tstamp);
+
+/**
  * struct clocksource - hardware abstraction for a free running counter
  *	Provides mostly state-free accessors to the underlying hardware.
+ *	This is the structure used for system time.
  *
  * @name:		ptr to clocksource name
  * @list:		list head for registration
kernel/time/clocksource.c +69 -0
index 9ed2eec..0d7a2cb 100644
@@ -31,6 +31,82 @@
 #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
 #include <linux/tick.h>
 
+void timecounter_init(struct timecounter *tc,
+		const struct cyclecounter *cc,
+		u64 start_tstamp)
+{
+	tc->cc = cc;
+	tc->cycle_last = cc->read(cc);
+	tc->nsec = start_tstamp;
+}
+EXPORT_SYMBOL(timecounter_init);
+
+/**
+ * clocksource_read_ns - get nanoseconds since last call of this function
+ * @tc:         Pointer to time counter
+ *
+ * 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 time counter initializes
+ * the time tracking and returns bogus results.
+ */
+static u64 timecounter_read_delta(struct timecounter *tc)
+{
+	cycle_t cycle_now, cycle_delta;
+	u64 ns_offset;
+
+	/* read cycle counter: */
+	cycle_now = tc->cc->read(tc->cc);
+
+	/* calculate the delta since the last timecounter_read_delta(): */
+	cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
+
+	/* convert to nanoseconds: */
+	ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta);
+
+	/* update time stamp of timecounter_read_delta() call: */
+	tc->cycle_last = cycle_now;
+
+	return ns_offset;
+}
+
+u64 timecounter_read(struct timecounter *tc)
+{
+	u64 nsec;
+
+	/* increment time by nanoseconds since last call */
+	nsec = timecounter_read_delta(tc);
+	nsec += tc->nsec;
+	tc->nsec = nsec;
+
+	return nsec;
+}
+EXPORT_SYMBOL(timecounter_read);
+
+u64 timecounter_cyc2time(struct timecounter *tc,
+			cycle_t cycle_tstamp)
+{
+	u64 cycle_delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask;
+	u64 nsec;
+
+	/*
+	 * Instead of always treating cycle_tstamp as more recent
+	 * than tc->cycle_last, detect when it is too far in the
+	 * future and treat it as old time stamp instead.
+	 */
+	if (cycle_delta > tc->cc->mask / 2) {
+		cycle_delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask;
+		nsec = tc->nsec - cyclecounter_cyc2ns(tc->cc, cycle_delta);
+	} else {

kernel/time/clocksource.c line 112

Quoted 10 lines
kernel/time/clocksource.c +7 -0
+		nsec = cyclecounter_cyc2ns(tc->cc, cycle_delta) + tc->nsec;
+	}
+
+	return nsec;
+}
+EXPORT_SYMBOL(timecounter_cyc2time);
+
 /* XXX - Would like a better way for initializing curr_clocksource */
 extern struct clocksource clocksource_jiffies;
 

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#14 lore raw

Re: [RFC PATCH 09/12] clocksource: allow usage independent of timekeeping.c

On Mon, 2008-12-15 at 16:26 +0000, John Stultz wrote:
[cyclecounter/timecounter]

Quoted 9 lines

Nice. The cyclecounter struct can work as a good base that I can shift the clocksource bits over to as I clean that up.

We will probably want to split this out down the road, but for now its small enough and related enough that I think its fine in the clocksource.h/c.

Also since Magnus has been working on it, does enable/disable accessors in the cyclecounter struct make sense for your hardware as well?

I don't think so. The usage model of the cyclecounter is that the hardware is owned by someone who initializes and controls it, including enable/disable. The abstract API with the read method is just there so that common utility code can access the hardware in a uniform way.

For example, the igb driver owns and uses the NIC time register. Disabling the NIC timer should be done together with disabling the NIC. This is different from traditional clocksources which are independent and controlled by the timing subsystem.

Quoted 4 lines

Also the corner cases on overflows (how we manage the state, should reads be deferred for too long) will need to be addressed, but I guess we can solve that when it becomes an issue. Just to be clear: none of the hardware you're submitting this round has wrapping issues?

It has 64 bit registers, so there is indeed no wrapping issue.

Quoted 2 lines

Otherwise,

Thanks, will add that.

Can you (or someone else) also look at clocksync.[ch]? David wanted to have that independently reviewed, too, before including it in netdev-next.

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#15 lore raw

Re: [RFC PATCH 09/12] clocksource: allow usage independent of timekeeping.c

In reply to John Stultz
Quoted 7 lines · John Stultz

Nice. The cyclecounter struct can work as a good base that I can shift the clocksource bits over to as I clean that up.

We will probably want to split this out down the road, but for now its small enough and related enough that I think its fine in the clocksource.h/c.

Quoted 8 lines

Also since Magnus has been working on it, does enable/disable accessors in the cyclecounter struct make sense for your hardware as well?

Also the corner cases on overflows (how we manage the state, should reads be deferred for too long) will need to be addressed, but I guess we can solve that when it becomes an issue. Just to be clear: none of the hardware you're submitting this round has wrapping issues? Or is that not the case?

Why wouldn't this just use a clocksource directly and not register it with the timekeeping? The cyclecounter is just a subset of the clocksource ..

Daniel

#16 lore raw

Re: [RFC PATCH 09/12] clocksource: allow usage independent of timekeeping.c

Quoted 18 lines · Daniel Walker
Quoted 7 lines · John Stultz

Nice. The cyclecounter struct can work as a good base that I can shift the clocksource bits over to as I clean that up.

We will probably want to split this out down the road, but for now its small enough and related enough that I think its fine in the clocksource.h/c.

Quoted 8 lines

Also since Magnus has been working on it, does enable/disable accessors in the cyclecounter struct make sense for your hardware as well?

Also the corner cases on overflows (how we manage the state, should reads be deferred for too long) will need to be addressed, but I guess we can solve that when it becomes an issue. Just to be clear: none of the hardware you're submitting this round has wrapping issues? Or is that not the case?

Quoted 3 lines

Why wouldn't this just use a clocksource directly and not register it with the timekeeping? The cyclecounter is just a subset of the clocksource ..

The very first revision of the patch did exactly that:
http://kerneltrap.org/mailarchive/linux-netdev/2008/11/19/4164204

The patch was smaller, but it also took some shortcuts (reusing fields meant to be used in a different way) and added other unused fields to the user of such an independent clocksource instance.

I agree with John that separate structures for different aspects of the problem (abstract API for read-only access to hardware; converting cycle counter into continuously increasing time counter) is the cleaner approach.

Signature · 6 lines
Best Regards, Patrick Ohly

The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.
#17 lore raw

Re: [RFC PATCH 02/12] net: infrastructure for hardware time stamping

In reply to Patrick Ohly

include/linux/skbuff.h struct sk_buff { · line 411

Quoted 7 lines · Patrick Ohly
include/linux/skbuff.h +2 -0
@@ -305,6 +406,8 @@ struct sk_buff {
                               ipvs_property:1,
                               peeked:1,
                               nf_trace:1;
+       /* not all of the bits in optional are used */
+       __u8                    optional;
       __be16                  protocol;

You do reliase that this is going to grow the sk_buff by at least 4 bytes and not 1?

Cheers,

Signature · 8 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#18 lore raw

Re: [RFC PATCH 02/12] net: infrastructure for hardware time stamping

Quoted 11 lines · Herbert Xu

include/linux/skbuff.h struct sk_buff { · line 411

Quoted 7 lines · Patrick Ohly
include/linux/skbuff.h +2 -0
@@ -305,6 +406,8 @@ struct sk_buff {
                               ipvs_property:1,
                               peeked:1,
                               nf_trace:1;
+       /* not all of the bits in optional are used */
+       __u8                    optional;
       __be16                  protocol;

You do reliase that this is going to grow the sk_buff by at least 4 bytes and not 1?

Yes. I should have been more explicit about that when talking about "adding one byte". At least it's better than adding 8 bytes of additional data, as in the previous patch.

I haven't checked it, but was told that sk_buff is already tightly packed. It didn't look like there was a better place to put the byte either.

Signature · 11 lines
Best Regards, Patrick Ohly

The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#19 lore raw
In reply to Patrick Ohly
Quoted 4 lines · Patrick Ohly

This is the third iteration of a patch series which adds a user space API for hardware time stamping of network packets and the infrastructure that implements that API. The igb driver is used as example for how a network driver can use this new infrastructure.

A new year, another month => time to bring this up once more. The latest revision of the patch series hasn't brought up further requests for improvement. There still is growing demand for this feature.

David, do you think it is ready to get included?

John acknowledged the changes to clocksource.h. clocksync is independent of everything else and not active unless called; if driver developers don't find it useful, it can be replaced/removed. That leaves the API, which hasn't triggered any comments so far. As proof that it works as intended I adapted PTPd to use it:
http://github.com/pohly/ptpd/tree/master

If further discussion of the API is necessary to get this into mainline, perhaps including the patches in netdev-next would help to encourage that discussion?

Is there anything I can do myself, like rebasing against the latest netdev-next?

Bye, Patrick

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#21 lore raw
Quoted 6 lines · David Miller

From: Patrick Ohly <[email protected]>
Date: Fri, 16 Jan 2009 11:36:04 +0100

Quoted 1 line

David, do you think it is ready to get included?

Resubmit the patch set before asking such questions.

Okay. I didn't want to spam the lists with just rebased patches if there were more fundamental objections against the current approach. I hope that this is no longer the case, so I'll post the current, rebased patch set as follow-up to this mail (because the description in the orginal mail of this thread still applies).

I personally consider the core infrastructure patches ready. If there are further comments I'd be happy to work on those, of course. The igb driver patches are more experimental, please don't include them.

I rebased the patches against net-next-2.6 as of today.

I tested them with the modified PTPd with and without hardware support on x86. With 64 bit kernel and user space both works. With 32 bit user space on a 64 bit kernel software-only time stamping works (thanks to the socket's compatibility layer), hardware support doesn't: the ifreq is passed to the right device driver, but the data pointer from a 32 bit process is not interpreted correctly by a 64 bit driver. If there is a way to handle this then please let me know - I didn't see how a device driver could distinguish between a 32 and 64 bit user process.

With a 32 bit kernel software time stamping works. I couldn't test hardware support because I couldn't get the igb driver to work. Even without any of the patches it failed to transmit packets (tested with net-next-2.6 sources and original Ubuntu 8.10 installation). I need to look into this problem further, but don't want to hold up the review of the patches.

Signature · 11 lines
Best Regards, Patrick Ohly

The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#22 lore raw

PATCH 1/12 net: new user space API for time stamping of incoming and outgoing packets

User space can request hardware and/or software time stamping. Reporting of the result(s) via a new control message is enabled separately for each field in the message because some of the fields may require additional computation and thus cause overhead. User space can tell the different kinds of time stamps apart and choose what suits its needs.

When a TX timestamp operation is requested, the TX skb will be cloned and the clone will be time stamped (in hardware or software) and added to the socket error queue of the skb, if the skb has a socket associated with it.

The actual TX timestamp will reach userspace as a RX timestamp on the cloned packet. If timestamping is requested and no timestamping is done in the device driver (potentially this may use hardware timestamping), it will be done in software after the device's start_hard_xmit routine.

---
 Documentation/networking/timestamping.txt          |  178 ++++++++
 Documentation/networking/timestamping/.gitignore   |    1 +
 Documentation/networking/timestamping/Makefile     |    3 +
 .../networking/timestamping/timestamping.c         |  469 ++++++++++++++++++++
 arch/alpha/include/asm/socket.h                    |    3 +
 arch/arm/include/asm/socket.h                      |    3 +
 arch/avr32/include/asm/socket.h                    |    3 +
 arch/blackfin/include/asm/socket.h                 |    3 +
 arch/cris/include/asm/socket.h                     |    3 +
 arch/h8300/include/asm/socket.h                    |    3 +
 arch/ia64/include/asm/socket.h                     |    3 +
 arch/mips/include/asm/socket.h                     |    3 +
 arch/parisc/include/asm/socket.h                   |    3 +
 arch/powerpc/include/asm/socket.h                  |    3 +
 arch/s390/include/asm/socket.h                     |    3 +
 arch/sh/include/asm/socket.h                       |    3 +
 arch/sparc/include/asm/socket.h                    |    3 +
 arch/x86/include/asm/socket.h                      |    3 +
 include/asm-frv/socket.h                           |    3 +
 include/asm-m32r/socket.h                          |    3 +
 include/asm-m68k/socket.h                          |    3 +
 include/asm-mn10300/socket.h                       |    3 +
 include/asm-xtensa/socket.h                        |    3 +
 include/linux/errqueue.h                           |    1 +
 include/linux/net_tstamp.h                         |  112 +++++
 include/linux/sockios.h                            |    3 +
 26 files changed, 824 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/networking/timestamping.txt
 create mode 100644 Documentation/networking/timestamping/.gitignore
 create mode 100644 Documentation/networking/timestamping/Makefile
 create mode 100644 Documentation/networking/timestamping/timestamping.c
 create mode 100644 include/linux/net_tstamp.h
Documentation/networking/timestamping.txt new file +178 -0
new file mode 100644
index 0000000..a681a65
@@ -0,0 +1,178 @@
+The existing interfaces for getting network packages time stamped are:
+
+* SO_TIMESTAMP
+  Generate time stamp for each incoming packet using the (not necessarily
+  monotonous!) system time. Result is returned via recv_msg() in a
+  control message as timeval (usec resolution).
+
+* SO_TIMESTAMPNS
+  Same time stamping mechanism as SO_TIMESTAMP, but returns result as
+  timespec (nsec resolution).
+
+* IP_MULTICAST_LOOP + SO_TIMESTAMP[NS]
+  Only for multicasts: approximate send time stamp by receiving the looped
+  packet and using its receive time stamp.
+
+The following interface complements the existing ones: receive time
+stamps can be generated and returned for arbitrary packets and much
+closer to the point where the packet is really sent. Time stamps can
+be generated in software (as before) or in hardware (if the hardware
+has such a feature).
+
+SO_TIMESTAMPING:
+
+Instructs the socket layer which kind of information is wanted. The
+parameter is an integer with some of the following bits set. Setting
+other bits is an error and doesn't change the current state.
+
+SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamp in hardware
+SOF_TIMESTAMPING_TX_SOFTWARE:  if SOF_TIMESTAMPING_TX_HARDWARE is off or
+                               fails, then do it in software
+SOF_TIMESTAMPING_RX_HARDWARE:  return the original, unmodified time stamp
+                               as generated by the hardware
+SOF_TIMESTAMPING_RX_SOFTWARE:  if SOF_TIMESTAMPING_RX_HARDWARE is off or
+                               fails, then do it in software
+SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp
+SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to
+                               the system time base
+SOF_TIMESTAMPING_SOFTWARE:     return system time stamp generated in
+                               software
+
+SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
+SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
+following control message:
+    struct scm_timestamping {
+           struct timespec systime;
+           struct timespec hwtimetrans;
+           struct timespec hwtimeraw;
+    };
+
+recvmsg() can be used to get this control message for regular incoming
+packets. For send time stamps the outgoing packet is looped back to
+the socket's error queue with the send time stamp(s) attached. It can
+be received with recvmsg(flags=MSG_ERRQUEUE). The call returns the
+original outgoing packet data including all headers preprended down to
+and including the link layer, the scm_timestamping control message and
+a sock_extended_err control message with ee_errno==ENOMSG and
+ee_origin==SO_EE_ORIGIN_TIMESTAMPING. A socket with such a pending
+bounced packet is ready for reading as far as select() is concerned.
+
+All three values correspond to the same event in time, but were
+generated in different ways. Each of these values may be empty (= all
+zero), in which case no such value was available. If the application
+is not interested in some of these values, they can be left blank to
+avoid the potential overhead of calculating them.
+
+systime is the value of the system time at that moment. This
+corresponds to the value also returned via SO_TIMESTAMP[NS]. If the
+time stamp was generated by hardware, then this field is
+empty. Otherwise it is filled in if SOF_TIMESTAMPING_SOFTWARE is
+set.
+
+hwtimeraw is the original hardware time stamp. Filled in if
+SOF_TIMESTAMPING_RAW_HARDWARE is set. No assumptions about its
+relation to system time should be made.
+
+hwtimetrans is the hardware time stamp transformed so that it
+corresponds as good as possible to system time. This correlation is
+not perfect; as a consequence, sorting packets received via different
+NICs by their hwtimetrans may differ from the order in which they were
+received. hwtimetrans may be non-monotonic even for the same NIC.
+Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support
+by the network device and will be empty without that support.
+
+
+SIOCSHWTSTAMP:
+
+Hardware time stamping must also be initialized for each device driver
+that is expected to do hardware time stamping. The parameter is:
+
+struct hwtstamp_config {
+    int flags;           /* no flags defined right now, must be zero */
+    int tx_type;         /* HWTSTAMP_TX_* */
+    int rx_filter;       /* HWTSTAMP_FILTER_* */
+};
+
+Desired behavior is passed into the kernel and to a specific device by
+calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose
+ifr_data points to a struct hwtstamp_config. The tx_type and
+rx_filter are hints to the driver what it is expected to do. If
+the requested fine-grained filtering for incoming packets is not
+supported, the driver may time stamp more than just the requested types
+of packets.
+
+A driver which supports hardware time stamping shall update the struct
+with the actual, possibly more permissive configuration. If the
+requested packets cannot be time stamped, then nothing should be
+changed and ERANGE shall be returned (in contrast to EINVAL, which
+indicates that SIOCSHWTSTAMP is not supported at all).
+
+Only a processes with admin rights may change the configuration. User
+space is responsible to ensure that multiple processes don't interfere
+with each other and that the settings are reset.
+
+/* possible values for hwtstamp_config->tx_type */
+enum {
+	/*
+	 * no outgoing packet will need hardware time stamping;
+	 * should a packet arrive which asks for it, no hardware
+	 * time stamping will be done
+	 */
+	HWTSTAMP_TX_OFF,
+
+	/*
+	 * enables hardware time stamping for outgoing packets;
+	 * the sender of the packet decides which are to be
+	 * time stamped by setting SOF_TIMESTAMPING_TX_SOFTWARE
+	 * before sending the packet
+	 */
+	HWTSTAMP_TX_ON,
+};
+
+/* possible values for hwtstamp_config->rx_filter */
+enum {
+	/* time stamp no incoming packet at all */
+	HWTSTAMP_FILTER_NONE,
+
+	/* time stamp any incoming packet */
+	HWTSTAMP_FILTER_ALL,
+
+        /* return value: time stamp all packets requested plus some others */
+        HWTSTAMP_FILTER_SOME,
+
+	/* PTP v1, UDP, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
+
+        ...
+};
+
+
+DEVICE IMPLEMENTATION
+
+A driver which supports hardware time stamping must support the
+SIOCSHWTSTAMP ioctl. Time stamps for received packets must be stored
+in the skb with skb_hwtstamp_set().
+
+Time stamps for outgoing packets are to be generated as follows:
+- In hard_start_xmit(), check if skb_hwtstamp_check_tx_hardware()
+  returns non-zero. If yes, then the driver is expected
+  to do hardware time stamping.
+- If this is possible for the skb and requested, then declare
+  that the driver is doing the time stamping by calling
+  skb_hwtstamp_tx_in_progress(). A driver not supporting
+  hardware time stamping doesn't do that. A driver must never
+  touch sk_buff::tstamp! It is used to store how time stamping
+  for an outgoing packets is to be done.
+- As soon as the driver has sent the packet and/or obtained a
+  hardware time stamp for it, it passes the time stamp back by
+  calling skb_hwtstamp_tx() with the original skb, the raw
+  hardware time stamp and a handle to the device (necessary
+  to convert the hardware time stamp to system time). If obtaining
+  the hardware time stamp somehow fails, then the driver should
+  not fall back to software time stamping. The rationale is that
+  this would occur at a later time in the processing pipeline
+  than other software time stamping and therefore could lead
+  to unexpected deltas between time stamps.
+- If the driver did not call skb_hwtstamp_tx_in_progress(), then
+  dev_hard_start_xmit() checks whether software time stamping
+  is wanted as fallback and potentially generates the time stamp.
Documentation/networking/timestamping/.gitignore new file +1 -0
new file mode 100644
index 0000000..71e81eb
@@ -0,0 +1 @@
+timestamping
Documentation/networking/timestamping/Makefile new file +3 -0
new file mode 100644
index 0000000..ce170d1
@@ -0,0 +1,3 @@
+CPPFLAGS = -I../../../include
+
+timestamping: timestamping.c
Documentation/networking/timestamping/timestamping.c new file +469 -0

469 lines not on this page · raw message

arch/alpha/include/asm/socket.h +3 -0
index a1057c2..5135249 100644
@@ -61,6 +61,9 @@
 #define SO_SECURITY_ENCRYPTION_NETWORK		21
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
arch/arm/include/asm/socket.h +3 -0
index 6817be9..5bd9130 100644
@@ -53,5 +53,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_SOCKET_H */
arch/avr32/include/asm/socket.h +3 -0
index 35863f2..707877b 100644
@@ -53,5 +53,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* __ASM_AVR32_SOCKET_H */
arch/blackfin/include/asm/socket.h +3 -0
index 2ca702e..a51a777 100644
@@ -52,5 +52,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif				/* _ASM_SOCKET_H */
arch/cris/include/asm/socket.h +3 -0
index 9df0ca8..ce30092 100644
@@ -55,6 +55,9 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_SOCKET_H */
 
arch/h8300/include/asm/socket.h +3 -0
index da2520d..660efa4 100644
@@ -53,5 +53,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_SOCKET_H */
arch/ia64/include/asm/socket.h +3 -0
index d5ef0aa..6afb493 100644
@@ -62,5 +62,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_IA64_SOCKET_H */
arch/mips/include/asm/socket.h +3 -0
index facc2d7..06ad2bc 100644
@@ -74,6 +74,9 @@ To add: #define SO_REUSEPORT 0x0200	/* Allow local address and port reuse.  */
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #ifdef __KERNEL__
 
arch/parisc/include/asm/socket.h +3 -0
index fba402c..885472b 100644
@@ -54,6 +54,9 @@
 
 #define SO_MARK			0x401f
 
+#define SO_TIMESTAMPING		0x4020
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
arch/powerpc/include/asm/socket.h +3 -0
index f5a4e16..bd15a06 100644
@@ -60,5 +60,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif	/* _ASM_POWERPC_SOCKET_H */
arch/s390/include/asm/socket.h +3 -0
index c786ab6..0cc8f3a 100644
@@ -61,5 +61,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_SOCKET_H */
arch/sh/include/asm/socket.h +3 -0
index 6d4bf65..b4697cb 100644
@@ -53,5 +53,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* __ASM_SH_SOCKET_H */
arch/sparc/include/asm/socket.h +3 -0
index bf50d0c..982a12f 100644
@@ -50,6 +50,9 @@
 
 #define SO_MARK			0x0022
 
+#define SO_TIMESTAMPING		0x0023
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002
arch/x86/include/asm/socket.h +3 -0
index 8ab9cc8..ca8bf2c 100644
@@ -54,4 +54,7 @@
 
 #define SO_MARK			36
 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
+
 #endif /* _ASM_X86_SOCKET_H */
include/asm-frv/socket.h +3 -0
index e51ca67..0539926 100644
@@ -53,6 +53,9 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_SOCKET_H */
 
include/asm-m32r/socket.h +3 -0
index 9a0e200..d100bae 100644
@@ -53,5 +53,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_M32R_SOCKET_H */
include/asm-m68k/socket.h +3 -0
index dbc64e9..1f425c6 100644
@@ -53,5 +53,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_SOCKET_H */
include/asm-mn10300/socket.h +3 -0
index 80af9c4..a633a06 100644
@@ -53,5 +53,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif /* _ASM_SOCKET_H */
include/asm-xtensa/socket.h +3 -0
index 6100682..5ada734 100644
@@ -64,5 +64,8 @@
 #define SCM_TIMESTAMPNS		SO_TIMESTAMPNS
 
 #define SO_MARK			36
+ 
+#define SO_TIMESTAMPING		37
+#define SCM_TIMESTAMPING	SO_TIMESTAMPING
 
 #endif	/* _XTENSA_SOCKET_H */
include/linux/errqueue.h +1 -0
index 92f8d4f..86d88dd 100644
@@ -16,6 +16,7 @@ struct sock_extended_err
 #define SO_EE_ORIGIN_LOCAL	1
 #define SO_EE_ORIGIN_ICMP	2
 #define SO_EE_ORIGIN_ICMP6	3
+#define SO_EE_ORIGIN_TIMESTAMPING 4
 
 #define SO_EE_OFFENDER(ee)	((struct sockaddr*)((ee)+1))
 
include/linux/net_tstamp.h new file +112 -0

112 lines not on this page · raw message

include/linux/sockios.h +3 -0
index abef759..241f179 100644
@@ -122,6 +122,9 @@
 #define SIOCBRADDIF	0x89a2		/* add interface to bridge      */
 #define SIOCBRDELIF	0x89a3		/* remove interface from bridge */
 
+/* hardware time stamping: parameters in linux/net_tstamp.h */
+#define SIOCSHWTSTAMP   0x89b0
+
 /* Device private ioctl calls */
 
 /*
Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#23 lore raw

PATCH 2/12 net: infrastructure for hardware time stamping

Instead of adding new members to struct sk_buff this patch introduces and uses a generic mechanism for extending skb: additional structures are allocated at the end of the data area, similar to the skb_shared_info. One new member of skb holds the information which of the optional structures are present, with one bit per structure. This allows fast checks whether certain information is present.

The actual address of an optional structure
is found by using a hard-coded ordering of these structures and adding up the size and alignment padding of the preceeding structs.

The new struct skb_shared_tx is used to transport time stamping instructions to the device driver (outgoing packets). The resulting hardware time stamps are returned via struct skb_shared_hwtstamps (incoming or sent packets), in all formats possibly needed by the rest of the kernel and user space (original raw hardware time stamp and converted to system time base). This replaces the problematic callbacks into the network driver used in earlier revisions of this patch.

Conceptionally the two structs are independent and use different bits in the new flags fields. This avoids the problem that dev_start_hard_xmit() cannot distinguish reliably between outgoing and incoming packets (it is called for looped multicast packets). But to avoid copying sent data, the space reserved for skb_shared_tx is increased so that this space can be reused for skb_shared_hwtstamps when sending back the packet to the originating socket.

TX time stamping is implemented in software if the device driver doesn't support hardware time stamping.

The new semantic for hardware/software time stamping around net_device->hard_start_xmit() is based on two assumptions about existing network device drivers which don't support hardware time stamping and know nothing about it:
- they leave the new skb_shared_tx struct unmodified
- the keep the connection to the originating socket in skb->sk alive, i.e., don't call skb_orphan()

Given that skb_shared_tx is new, the first assumption is safe. The second is only true for some drivers. As a result, software TX time stamping currently works with the bnx2 driver, but not with the unmodified igb driver (the two drivers this patch series was tested with).

---
 include/linux/skbuff.h |  196 ++++++++++++++++++++++++++++++++++++++++++++++--
 net/core/dev.c         |   33 ++++++++-
 net/core/skbuff.c      |  153 ++++++++++++++++++++++++++++++++------
 3 files changed, 351 insertions(+), 31 deletions(-)
include/linux/skbuff.h +189 -7
index cf2cb50..8286f76 100644
@@ -156,6 +156,105 @@ struct skb_shared_info {
 #endif
 };
 
+#define HAVE_HW_TIME_STAMP
+
+/**
+ * skb_shared_hwtstamps - optional hardware time stamps
+ *
+ * @hwtstamp:	hardware time stamp transformed into duration
+ *		since arbitrary point in time
+ * @syststamp:	hwtstamp transformed to system time base
+ *
+ * Software time stamps generated by ktime_get_real() are stored in
+ * skb->tstamp. The relation between the different kinds of time
+ * stamps is as follows:
+ *
+ * syststamp and tstamp can be compared against each other in
+ * arbitrary combinations.  The accuracy of a
+ * syststamp/tstamp/"syststamp from other device" comparison is
+ * limited by the accuracy of the transformation into system time
+ * base. This depends on the device driver and its underlying
+ * hardware.
+ *
+ * hwtstamps can only be compared against other hwtstamps from
+ * the same device.
+ *
+ * This additional structure has to be allocated together with
+ * the data buffer and is shared between clones.
+ */
+struct skb_shared_hwtstamps {
+	ktime_t	hwtstamp;
+	ktime_t	syststamp;
+};
+
+/**
+ * skb_shared_tx - optional instructions for time stamping of outgoing packets
+ *
+ * @hardware:		generate hardware time stamp
+ * @software:		generate software time stamp
+ * @in_progress:	device driver is going to provide
+ *			hardware time stamp
+ *
+ * This additional structure has to be allocated together with the
+ * data buffer and is shared between clones. Its space is reused
+ * in skb_tstamp_tx() for skb_shared_hwtstamps and therefore it
+ * has to be larger than strictly necessary (handled in skbuff.c).
+ */
+union skb_shared_tx {
+	struct {
+		__u8	hardware:1,
+			software:1,
+			in_progress:1;
+	};
+	__u8 flags;
+};
+
+/*
+ * Flags which control how &struct sk_buff is to be/was allocated.
+ * The &struct skb_shared_info always comes at sk_buff->end, then
+ * all of the optional structs in the order defined by their
+ * flags. Each structure is aligned so that it is at a multiple
+ * of 8 or its own size, whatever is smaller. Putting structs
+ * with less strict alignment requirements at the end increases
+ * the chance that no padding is needed.
+ *
+ * SKB_FLAGS_TXTSTAMP could be combined with SKB_FLAGS_HWTSTAMPS
+ * (outgoing packets have &union skb_shared_tx, incoming
+ * &struct skb_shared_hwtstamps), but telling apart one from
+ * the other is ambiguous: when a multicast packet is looped back,
+ * it has to be considered incoming, but it then passes through
+ * dev_hard_start_xmit() once more. Better avoid such ambiguities,
+ * in particular as it doesn't save any space. One additional byte
+ * is needed in any case.
+ *
+ * SKB_FLAGS_CLONE replaces the true/false integer fclone parameter in
+ * __alloc_skb(). Clones are marked as before in sk_buff->cloned.
+ *
+ * Similarly, SKB_FLAGS_NOBLOCK is used in place of a special noblock
+ * parameter in sock_alloc_send_skb().
+ *
+ * When adding optional structs, remember to update skb_optional_sizes
+ * in skbuff.c!
+ */
+enum {
+	/*
+	 * one byte holds the lower order flags in struct sk_buff,
+	 * so we could add more structs without additional costs
+	 */
+	SKB_FLAGS_OPTIONAL_HWTSTAMPS = 1 << 0,
+	SKB_FLAGS_OPTIONAL_TX = 1 << 1,
+
+	/* number of bits used for optional structures */
+	SKB_FLAGS_OPTIONAL_NUM = 2,
+
+	/*
+	 * the following flags only affect how the skb is allocated,
+	 * they are not stored like the ones above
+	 */
+	SKB_FLAGS_CLONE = 1 << 8,
+	SKB_FLAGS_NOBLOCK = 1 << 9,
+};
+
 /* We divide dataref into two halves.  The higher 16 bits hold references
  * to the payload part of skb->data.  The lower 16 bits hold references to
  * the entire skb->data.  A clone of a headerless skb holds the length of
@@ -228,6 +327,8 @@ typedef unsigned char *sk_buff_data_t;
  *	@ip_summed: Driver fed us an IP checksum
  *	@priority: Packet queueing priority
  *	@users: User count - see {datagram,tcp}.c
+ *	@optional: a combination of SKB_FLAGS_OPTIONAL_* flags, indicates
+ *		which of the corresponding structs were allocated
  *	@protocol: Packet protocol from driver
  *	@truesize: Buffer size 
  *	@head: Head of buffer
@@ -305,6 +406,8 @@ struct sk_buff {
 				ipvs_property:1,
 				peeked:1,
 				nf_trace:1;
+	/* not all of the bits in optional are used */
+	__u8			optional;
 	__be16			protocol;
 
 	void			(*destructor)(struct sk_buff *skb);
@@ -374,18 +477,18 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
 
 extern void kfree_skb(struct sk_buff *skb);
 extern void	       __kfree_skb(struct sk_buff *skb);
-extern struct sk_buff *__alloc_skb(unsigned int size,
-				   gfp_t priority, int fclone, int node);
+extern struct sk_buff *__alloc_skb_flags(unsigned int size,
+					gfp_t priority, int flags, int node);
 static inline struct sk_buff *alloc_skb(unsigned int size,
 					gfp_t priority)
 {
-	return __alloc_skb(size, priority, 0, -1);
+	return __alloc_skb_flags(size, priority, 0, -1);
 }
 
 static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
 					       gfp_t priority)
 {
-	return __alloc_skb(size, priority, 1, -1);
+	return __alloc_skb_flags(size, priority, SKB_FLAGS_CLONE, -1);
 }
 
 extern int skb_recycle_check(struct sk_buff *skb, int skb_size);
@@ -469,6 +572,29 @@ static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 #define skb_shinfo(SKB)	((struct skb_shared_info *)(skb_end_pointer(SKB)))
 
 /**
+ * __skb_get_optional - returns pointer to the requested structure
+ *
+ * @optional:	one of the SKB_FLAGS_OPTIONAL_* constants
+ *
+ * The caller must check that the structure is actually in the skb.
+ */
+extern void *__skb_get_optional(struct sk_buff *skb, int optional);
+
+static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
+{
+	return (skb->optional & SKB_FLAGS_OPTIONAL_HWTSTAMPS) ?
+		__skb_get_optional(skb, SKB_FLAGS_OPTIONAL_HWTSTAMPS) :
+		NULL;
+}
+
+static inline union skb_shared_tx *skb_tx(struct sk_buff *skb)
+{
+	return (skb->optional & SKB_FLAGS_OPTIONAL_TX) ?
+		__skb_get_optional(skb, SKB_FLAGS_OPTIONAL_TX) :
+		NULL;
+}
+
+/**
  *	skb_queue_empty - check if a queue is empty
  *	@list: queue head
  *
@@ -1399,8 +1525,33 @@ static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
 
 extern struct sk_buff *dev_alloc_skb(unsigned int length);
 
-extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
-		unsigned int length, gfp_t gfp_mask);
+/**
+ *	__netdev_alloc_skb_internal - allocate an skbuff for rx on a specific device
+ *	@dev: network device to receive on
+ *	@length: length to allocate
+ *	@flags: SKB_FLAGS_* mask
+ *	@gfp_mask: get_free_pages mask, passed to alloc_skb
+ *
+ *	Allocate a new &sk_buff and assign it a usage count of one. The
+ *	buffer has unspecified headroom built in. Users should allocate
+ *	the headroom they think they need without accounting for the
+ *	built in space. The built in space is used for optimisations.
+ *
+ *	%NULL is returned if there is no free memory.
+ *
+ *	This function takes the full set of parameters. There are aliases
+ *	with a smaller number of parameters.
+ */
+extern struct sk_buff *__netdev_alloc_skb_internal(struct net_device *dev,
+						unsigned int length, int flags,
+						gfp_t gfp_mask);
+
+static inline struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
+						unsigned int length,
+						gfp_t gfp_mask)
+{
+	return __netdev_alloc_skb_internal(dev, length, 0, gfp_mask);
+}
 
 /**
  *	netdev_alloc_skb - allocate an skbuff for rx on a specific device
@@ -1418,7 +1569,12 @@ extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
 static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
 		unsigned int length)
 {
-	return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
+	return __netdev_alloc_skb_internal(dev, length, 0, GFP_ATOMIC);
+}
+static inline struct sk_buff *netdev_alloc_skb_flags(struct net_device *dev,
+						unsigned int length, int flags)
+{
+	return __netdev_alloc_skb_internal(dev, length, flags, GFP_ATOMIC);
 }
 
 extern struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask);
@@ -1735,6 +1891,11 @@ static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb,
 
 extern void skb_init(void);
 
+static inline ktime_t skb_get_ktime(const struct sk_buff *skb)
+{
+	return skb->tstamp;
+}
+
 /**
  *	skb_get_timestamp - get timestamp from a skb
  *	@skb: skb to get stamp from
@@ -1749,6 +1910,11 @@ static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *
 	*stamp = ktime_to_timeval(skb->tstamp);
 }
 
+static inline void skb_get_timestampns(const struct sk_buff *skb, struct timespec *stamp)
+{
+	*stamp = ktime_to_timespec(skb->tstamp);
+}
+
 static inline void __net_timestamp(struct sk_buff *skb)
 {
 	skb->tstamp = ktime_get_real();
@@ -1764,6 +1930,22 @@ static inline ktime_t net_invalid_timestamp(void)
 	return ktime_set(0, 0);
 }
 
+/**
+ * skb_tstamp_tx - queue clone of skb with send time stamps
+ * @orig_skb:	the original outgoing packet
+ * @hwtstamps:	hardware time stamps, may be NULL if not available
+ *
+ * If the skb has a socket associated, then this function clones the
+ * skb (thus sharing the actual data and optional structures), stores
+ * the optional hardware time stamping information (if non NULL) or
+ * generates a software time stamp (otherwise), then queues the clone
+ * to the error queue of the socket.  Errors are silently ignored.
+ *
+ * May only be called on skbs which have a skb_shared_tx!
+ */
+extern void skb_tstamp_tx(struct sk_buff *orig_skb,
+			struct skb_shared_hwtstamps *hwtstamps);
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
net/core/dev.c +31 -2
index 4464240..93b2ac9 100644
@@ -1658,10 +1658,22 @@ static int dev_gso_segment(struct sk_buff *skb)
 	return 0;
 }
 
+static void tstamp_tx(struct sk_buff *skb)
+{
+	union skb_shared_tx *shtx =
+		skb_tx(skb);
+	if (unlikely(shtx &&
+			shtx->software &&
+			!shtx->in_progress)) {
+		skb_tstamp_tx(skb, NULL);
+	}
+}
+
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 			struct netdev_queue *txq)
 {
 	const struct net_device_ops *ops = dev->netdev_ops;
+	int rc;
 
 	prefetch(&dev->netdev_ops->ndo_start_xmit);
 	if (likely(!skb->next)) {
@@ -1675,13 +1687,29 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 				goto gso;
 		}
 
-		return ops->ndo_start_xmit(skb, dev);
+		rc = ops->ndo_start_xmit(skb, dev);
+		/*
+		 * TODO: if skb_orphan() was called by
+		 * dev->hard_start_xmit() (for example, the unmodified
+		 * igb driver does that; bnx2 doesn't), then
+		 * skb_tx_software_timestamp() will be unable to send
+		 * back the time stamp.
+		 *
+		 * How can this be prevented? Always create another
+		 * reference to the socket before calling
+		 * dev->hard_start_xmit()? Prevent that skb_orphan()
+		 * does anything in dev->hard_start_xmit() by clearing
+		 * the skb destructor before the call and restoring it
+		 * afterwards, then doing the skb_orphan() ourselves?
+		 */
+		if (likely(!rc))
+			tstamp_tx(skb);
+		return rc;
 	}
 
 gso:
 	do {
 		struct sk_buff *nskb = skb->next;
-		int rc;
 
 		skb->next = nskb->next;
 		nskb->next = NULL;
@@ -1691,6 +1719,7 @@ gso:
 			skb->next = nskb;
 			return rc;
 		}
+		tstamp_tx(skb);
 		if (unlikely(netif_tx_queue_stopped(txq) && skb->next))
 			return NETDEV_TX_BUSY;
 	} while (skb->next);
net/core/skbuff.c +131 -22

224 lines not on this page · raw message

Signature · 1 line
1.5.5.3
#24 lore raw

PATCH 3/12 net: socket infrastructure for SO_TIMESTAMPING

The overlap with the old SO_TIMESTAMP[NS] options is handled so that time stamping in software (net_enable_timestamp()) is enabled when SO_TIMESTAMP[NS] and/or SO_TIMESTAMPING_RX_SOFTWARE is set. It's disabled if all of these are off.

---
 include/net/sock.h |   40 ++++++++++++++++++++++--
 net/compat.c       |   19 +++++++----
 net/core/sock.c    |   79 ++++++++++++++++++++++++++++++++++++++++-------
 net/socket.c       |   86 ++++++++++++++++++++++++++++++++++++++++------------
 4 files changed, 182 insertions(+), 42 deletions(-)
include/net/sock.h +37 -3
index 5a3a151..36807e4 100644
@@ -158,7 +158,7 @@ struct sock_common {
   *	@sk_allocation: allocation mode
   *	@sk_sndbuf: size of send buffer in bytes
   *	@sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
-  *		   %SO_OOBINLINE settings
+  *		   %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
   *	@sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
   *	@sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
   *	@sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
@@ -488,6 +488,13 @@ enum sock_flags {
 	SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */
 	SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */
 	SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */
+	SOCK_TIMESTAMPING_TX_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_TX_HARDWARE */
+	SOCK_TIMESTAMPING_TX_SOFTWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_TX_SOFTWARE */
+	SOCK_TIMESTAMPING_RX_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_RX_HARDWARE */
+	SOCK_TIMESTAMPING_RX_SOFTWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_RX_SOFTWARE */
+	SOCK_TIMESTAMPING_SOFTWARE,    /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_SOFTWARE */
+	SOCK_TIMESTAMPING_RAW_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_RAW_HARDWARE */
+	SOCK_TIMESTAMPING_SYS_HARDWARE, /* %SO_TIMESTAMPING %SOF_TIMESTAMPING_SYS_HARDWARE */
 };
 
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1342,13 +1349,40 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
 	ktime_t kt = skb->tstamp;
 
-	if (sock_flag(sk, SOCK_RCVTSTAMP))
+	/*
+	 * generate control messages if
+	 * - receive time stamping in software requested (SOCK_RCVTSTAMP
+	 *   or SOCK_TIMESTAMPING_RX_SOFTWARE)
+	 * - software time stamp available and wanted (SOCK_TIMESTAMPING_SOFTWARE)
+	 * - hardware time stamps available and wanted (SOCK_TIMESTAMPING_SYS_HARDWARE
+	 *   or SOCK_TIMESTAMPING_RAW_HARDWARE)
+	 */
+	if (sock_flag(sk, SOCK_RCVTSTAMP) ||
+		sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE) ||
+		(kt.tv64 && sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) ||
+		((skb->optional & SKB_FLAGS_OPTIONAL_HWTSTAMPS) &&
+			(sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) ||
+				sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE))))
 		__sock_recv_timestamp(msg, sk, skb);
 	else
 		sk->sk_stamp = kt;
 }
 
 /**
+ * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
+ * @msg:	outgoing packet
+ * @sk:		socket sending this packet
+ * @shtx:	filled with instructions for time stamping
+ *
+ * Currently only depends on SOCK_TIMESTAMPING* flags. Returns error code if
+ * parameters are invalid.
+ */
+extern int sock_tx_timestamp(struct msghdr *msg,
+			struct sock *sk,
+			union skb_shared_tx *shtx);
+
+
+/**
  * sk_eat_skb - Release a skb if it is no longer needed
  * @sk: socket to eat this skb from
  * @skb: socket buffer to eat
@@ -1416,7 +1450,7 @@ static inline struct sock *skb_steal_sock(struct sk_buff *skb)
 	return NULL;
 }
 
-extern void sock_enable_timestamp(struct sock *sk);
+extern void sock_enable_timestamp(struct sock *sk, int flag);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
 extern int sock_get_timestampns(struct sock *, struct timespec __user *);
 
net/compat.c +12 -7
index a3a2ba0..fb01ed9 100644
@@ -216,7 +216,7 @@ Efault:
 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
 {
 	struct compat_timeval ctv;
-	struct compat_timespec cts;
+	struct compat_timespec cts[3];
 	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 	struct compat_cmsghdr cmhdr;
 	int cmlen;
@@ -233,12 +233,17 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
 		data = &ctv;
 		len = sizeof(ctv);
 	}
-	if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS) {
+	if (level == SOL_SOCKET &&
+		(type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
+		int count = type == SCM_TIMESTAMPNS ? 1 : 3;
+		int i;
 		struct timespec *ts = (struct timespec *)data;
-		cts.tv_sec = ts->tv_sec;
-		cts.tv_nsec = ts->tv_nsec;
+		for (i = 0; i < count; i++) {
+			cts[i].tv_sec = ts[i].tv_sec;
+			cts[i].tv_nsec = ts[i].tv_nsec;
+		}
 		data = &cts;
-		len = sizeof(cts);
+		len = sizeof(cts[0]) * count;
 	}
 
 	cmlen = CMSG_COMPAT_LEN(len);
@@ -455,7 +460,7 @@ int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
 	struct timeval tv;
 
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
-		sock_enable_timestamp(sk);
+		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
 	tv = ktime_to_timeval(sk->sk_stamp);
 	if (tv.tv_sec == -1)
 		return err;
@@ -479,7 +484,7 @@ int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *usersta
 	struct timespec ts;
 
 	if (!sock_flag(sk, SOCK_TIMESTAMP))
-		sock_enable_timestamp(sk);
+		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
 	ts = ktime_to_timespec(sk->sk_stamp);
 	if (ts.tv_sec == -1)
 		return err;
net/core/sock.c +67 -12

135 lines not on this page · raw message

net/socket.c +66 -20

105 lines not on this page · raw message

Signature · 1 line
1.5.5.3
#25 lore raw

PATCH 4/12 sockets: allow allocating skb with optional structures

The internal sock_alloc_send_pskb() is now exposed as sock_alloc_send_skb_flags() and takes a flags parameter with additional instructions for how the skb is to be allocated. This is necessary for adding send time stamping information to outgoing packets.

sock_alloc_send_skb() is turned into a simple wrapper which preserves compatibility with code that passes a boolean "nblock" instead of the flags bitmask.

sock_alloc_send_pskb() was never called with non-zero data_len, therefore the obsolete code and parameter were removed.

---
 include/net/sock.h |   17 +++++++++++++----
 net/core/sock.c    |   50 +++++++-------------------------------------------
 2 files changed, 20 insertions(+), 47 deletions(-)
include/net/sock.h +13 -4
index 36807e4..6cb120c 100644
@@ -948,10 +948,19 @@ extern int			sock_setsockopt(struct socket *sock, int level,
 extern int			sock_getsockopt(struct socket *sock, int level,
 						int op, char __user *optval, 
 						int __user *optlen);
-extern struct sk_buff 		*sock_alloc_send_skb(struct sock *sk,
-						     unsigned long size,
-						     int noblock,
-						     int *errcode);
+extern struct sk_buff		*sock_alloc_send_skb_flags(struct sock *sk,
+						unsigned long size,
+						int flags,
+						int *errcode);
+inline static struct sk_buff 	*sock_alloc_send_skb(struct sock *sk,
+						unsigned long size,
+						int noblock,
+						int *errcode)
+{
+	return sock_alloc_send_skb_flags(sk, size,
+					noblock ? SKB_FLAGS_NOBLOCK : 0,
+					errcode);
+}
 extern void *sock_kmalloc(struct sock *sk, int size,
 			  gfp_t priority);
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
net/core/sock.c +7 -43

82 lines not on this page · raw message

Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#26 lore raw

PATCH 5/12 ip: support for TX timestamps on UDP and RAW sockets

Instructions for time stamping outgoing packets are take from the socket layer and later copied into the new skb.

---
 Documentation/networking/timestamping.txt |    2 ++
 include/net/ip.h                          |    1 +
 net/can/raw.c                             |   14 +++++++++++---
 net/ipv4/icmp.c                           |    2 ++
 net/ipv4/ip_output.c                      |   12 ++++++++++--
 net/ipv4/raw.c                            |    1 +
 net/ipv4/udp.c                            |    4 ++++
 7 files changed, 31 insertions(+), 5 deletions(-)
Documentation/networking/timestamping.txt +2 -0
index a681a65..0e58b45 100644
@@ -56,6 +56,8 @@ and including the link layer, the scm_timestamping control message and
 a sock_extended_err control message with ee_errno==ENOMSG and
 ee_origin==SO_EE_ORIGIN_TIMESTAMPING. A socket with such a pending
 bounced packet is ready for reading as far as select() is concerned.
+If the outgoing packet has to be fragmented, then only the first
+fragment is time stamped and returned to the sending socket.
 
 All three values correspond to the same event in time, but were
 generated in different ways. Each of these values may be empty (= all
include/net/ip.h +1 -0
index 1086813..4ac7577 100644
@@ -55,6 +55,7 @@ struct ipcm_cookie
 	__be32			addr;
 	int			oif;
 	struct ip_options	*opt;
+	union skb_shared_tx	shtx;
 };
 
 #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
net/can/raw.c +11 -3
index 27aab63..1f2111d 100644
@@ -618,6 +618,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 	struct raw_sock *ro = raw_sk(sk);
 	struct sk_buff *skb;
 	struct net_device *dev;
+	union skb_shared_tx shtx;
 	int ifindex;
 	int err;
 
@@ -639,8 +640,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 	if (!dev)
 		return -ENXIO;
 
-	skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
-				  &err);
+	err = sock_tx_timestamp(msg, sk, &shtx);
+	if (err < 0)
+		return err;
+
+	skb = sock_alloc_send_skb_flags(sk, size,
+				((msg->msg_flags & MSG_DONTWAIT) ? SKB_FLAGS_NOBLOCK : 0) |
+					(shtx.flags ? SKB_FLAGS_OPTIONAL_TX : 0),
+				&err);
 	if (!skb)
 		goto put_dev;
 
@@ -649,7 +656,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 		goto free_skb;
 	skb->dev = dev;
 	skb->sk  = sk;
-
+	if (shtx.flags)
+		*skb_tx(skb) = shtx;
 	err = can_send(skb, ro->loopback);
 
 	dev_put(dev);
net/ipv4/icmp.c +2 -0
index 705b33b..382800a 100644
@@ -375,6 +375,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 	inet->tos = ip_hdr(skb)->tos;
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 	if (icmp_param->replyopts.optlen) {
 		ipc.opt = &icmp_param->replyopts;
 		if (ipc.opt->srr)
@@ -532,6 +533,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 	inet_sk(sk)->tos = tos;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
+	ipc.shtx.flags = 0;
 
 	{
 		struct flowi fl = {
net/ipv4/ip_output.c +10 -2
index 8ebe86d..ed92f0b 100644
@@ -923,9 +923,11 @@ alloc_new_skb:
 				alloclen += rt->u.dst.trailer_len;
 
 			if (transhdrlen) {
-				skb = sock_alloc_send_skb(sk,
+				skb = sock_alloc_send_skb_flags(sk,
 						alloclen + hh_len + 15,
-						(flags & MSG_DONTWAIT), &err);
+				       		((flags & MSG_DONTWAIT) ? SKB_FLAGS_NOBLOCK : 0) |
+							(ipc->shtx.flags ? SKB_FLAGS_OPTIONAL_TX : 0),
+						&err);
 			} else {
 				skb = NULL;
 				if (atomic_read(&sk->sk_wmem_alloc) <=
@@ -935,6 +937,9 @@ alloc_new_skb:
 							   sk->sk_allocation);
 				if (unlikely(skb == NULL))
 					err = -ENOBUFS;
+				else
+					/* only the initial fragment is time stamped */
+					ipc->shtx.flags = 0;
 			}
 			if (skb == NULL)
 				goto error;
@@ -945,6 +950,8 @@ alloc_new_skb:
 			skb->ip_summed = csummode;
 			skb->csum = 0;
 			skb_reserve(skb, hh_len);
+			if (ipc->shtx.flags)
+				*skb_tx(skb) = ipc->shtx;
 
 			/*
 			 *	Find where to start putting bytes.
@@ -1364,6 +1371,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
 
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 
 	if (replyopts.opt.optlen) {
 		ipc.opt = &replyopts.opt;
net/ipv4/raw.c +1 -0
index dff8bc4..f774651 100644
@@ -493,6 +493,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
 	ipc.addr = inet->saddr;
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 	ipc.oif = sk->sk_bound_dev_if;
 
 	if (msg->msg_controllen) {
net/ipv4/udp.c +4 -0
index cf5ab05..bbf1a6d 100644
@@ -573,6 +573,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		return -EOPNOTSUPP;
 
 	ipc.opt = NULL;
+	ipc.shtx.flags = 0;
 
 	if (up->pending) {
 		/*
@@ -620,6 +621,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	ipc.addr = inet->saddr;
 
 	ipc.oif = sk->sk_bound_dev_if;
+	err = sock_tx_timestamp(msg, sk, &ipc.shtx);
+	if (err)
+		return err;
 	if (msg->msg_controllen) {
 		err = ip_cmsg_send(sock_net(sk), msg, &ipc);
 		if (err)
Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#27 lore raw

PATCH 6/12 debug: NULL pointer check in ip_output

---
 net/ipv4/ip_output.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)
net/ipv4/ip_output.c +8 -2
index ed92f0b..03a6706 100644
@@ -950,8 +950,14 @@ alloc_new_skb:
 			skb->ip_summed = csummode;
 			skb->csum = 0;
 			skb_reserve(skb, hh_len);
-			if (ipc->shtx.flags)
-				*skb_tx(skb) = ipc->shtx;
+			if (ipc->shtx.flags) {
+				if (skb_tx(skb)) 
+					*skb_tx(skb) = ipc->shtx;
+				else
+					printk(KERN_DEBUG
+						"ERROR: skb with flags %x and no tx ptr\n",
+						ipc->shtx.flags);
+			}
 
 			/*
 			 *	Find where to start putting bytes.
Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#28 lore raw

PATCH 7/12 net: pass new SIOCSHWTSTAMP through to device drivers

---
 fs/compat_ioctl.c |    1 +
 net/core/dev.c    |    2 ++
 2 files changed, 3 insertions(+), 0 deletions(-)
fs/compat_ioctl.c +1 -0
index 5235c67..a5001a6 100644
@@ -2555,6 +2555,7 @@ HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc)
+HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc)
 
 /* ioctls used by appletalk ddp.c */
 HANDLE_IOCTL(SIOCATALKDIFADDR, dev_ifsioc)
net/core/dev.c +2 -0
index 93b2ac9..370c9f1 100644
@@ -3864,6 +3864,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
 			    cmd == SIOCSMIIREG ||
 			    cmd == SIOCBRADDIF ||
 			    cmd == SIOCBRDELIF ||
+			    cmd == SIOCSHWTSTAMP ||
 			    cmd == SIOCWANDEV) {
 				err = -EOPNOTSUPP;
 				if (ops->ndo_do_ioctl) {
@@ -4018,6 +4019,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 		case SIOCBONDCHANGEACTIVE:
 		case SIOCBRADDIF:
 		case SIOCBRDELIF:
+		case SIOCSHWTSTAMP:
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			/* fall through */
Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#29 lore raw

PATCH 8/12 igb: stub support for SIOCSHWTSTAMP

---
 drivers/net/igb/igb_main.c |   30 ++++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)
drivers/net/igb/igb_main.c +30 -0
index 022794e..d26dacb 100644
@@ -34,6 +34,7 @@
 #include <linux/ipv6.h>
 #include <net/checksum.h>
 #include <net/ip6_checksum.h>
+#include <linux/net_tstamp.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
@@ -4146,6 +4147,33 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 }
 
 /**
+ * igb_hwtstamp_ioctl - control hardware time stamping
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ *
+ * Currently cannot enable any kind of hardware time stamping, but
+ * supports SIOCSHWTSTAMP in general.
+ **/
+static int igb_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct hwtstamp_config config;
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	/* reserved for future extensions */
+	if (config.flags)
+		return -EINVAL;
+
+	if (config.tx_type == HWTSTAMP_TX_OFF &&
+		config.rx_filter == HWTSTAMP_FILTER_NONE)
+		return 0;
+
+	return -ERANGE;
+}
+
+/**
  * igb_ioctl -
  * @netdev:
  * @ifreq:
@@ -4158,6 +4186,8 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 	case SIOCGMIIREG:
 	case SIOCSMIIREG:
 		return igb_mii_ioctl(netdev, ifr, cmd);
+	case SIOCSHWTSTAMP:
+		return igb_hwtstamp_ioctl(netdev, ifr, cmd);
 	default:
 		return -EOPNOTSUPP;
 	}
Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#30 lore raw

PATCH 9/12 clocksource: allow usage independent of timekeeping.c

So far struct clocksource acted as the interface between time/timekeeping.c and hardware. This patch generalizes the concept so that a similar interface can also be used in other contexts. For that it introduces new structures and related functions *without* touching the existing struct clocksource.

The reasons for adding these new structures to clocksource.[ch] are
* the APIs are clearly related
* struct clocksource could be cleaned up to use the new structs
* avoids proliferation of files with similar names (timesource.h? timecounter.h?)

As outlined in the discussion with John Stultz, this patch adds
* struct cyclecounter: stateless API to hardware which counts clock cycles
* struct timecounter: stateful utility code built on a cyclecounter which provides a nanosecond counter
* only the function to read the nanosecond counter; deltas are used internally and not exposed to users of timecounter

The code does no locking of the shared state. It must be called at least as often as the cycle counter wraps around to detect these wrap arounds. Both is the responsibility of the timecounter user.

---
 include/linux/clocksource.h |   99 +++++++++++++++++++++++++++++++++++++++++++
 kernel/time/clocksource.c   |   76 +++++++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+), 0 deletions(-)
include/linux/clocksource.h +99 -0
index f88d32f..d379189 100644
@@ -22,8 +22,107 @@ typedef u64 cycle_t;
 struct clocksource;
 
 /**
+ * struct cyclecounter - hardware abstraction for a free running counter
+ *	Provides completely state-free accessors to the underlying hardware.
+ *	Depending on which hardware it reads, the cycle counter may wrap
+ *	around quickly. Locking rules (if necessary) have to be defined
+ *	by the implementor and user of specific instances of this API.
+ *
+ * @read:		returns the current cycle value
+ * @mask:		bitmask for two's complement
+ *			subtraction of non 64 bit counters,
+ *			see CLOCKSOURCE_MASK() helper macro
+ * @mult:		cycle to nanosecond multiplier
+ * @shift:		cycle to nanosecond divisor (power of two)
+ */
+struct cyclecounter {
+	cycle_t (*read)(const struct cyclecounter *cc);
+	cycle_t mask;
+	u32 mult;
+	u32 shift;
+};
+
+/**
+ * struct timecounter - layer above a %struct cyclecounter which counts nanoseconds
+ *	Contains the state needed by timecounter_read() to detect
+ *	cycle counter wrap around. Initialize with
+ *	timecounter_init(). Also used to convert cycle counts into the
+ *	corresponding nanosecond counts with timecounter_cyc2time(). Users
+ *	of this code are responsible for initializing the underlying
+ *	cycle counter hardware, locking issues and reading the time
+ *	more often than the cycle counter wraps around. The nanosecond
+ *	counter will only wrap around after ~585 years.
+ *
+ * @cc:			the cycle counter used by this instance
+ * @cycle_last:		most recent cycle counter value seen by timecounter_read()
+ * @nsec:		
+ */
+struct timecounter {
+	const struct cyclecounter *cc;
+	cycle_t cycle_last;
+	u64 nsec;
+};
+
+/**
+ * cyclecounter_cyc2ns - converts cycle counter cycles to nanoseconds
+ * @tc:		Pointer to cycle counter.
+ * @cycles:	Cycles
+ *
+ * XXX - This could use some mult_lxl_ll() asm optimization. Same code
+ * as in cyc2ns, but with unsigned result.
+ */
+static inline u64 cyclecounter_cyc2ns(const struct cyclecounter *cc, cycle_t cycles)
+{
+	u64 ret = (u64)cycles;
+	ret = (ret * cc->mult) >> cc->shift;
+	return ret;
+}
+
+/**
+ * timecounter_init - initialize a time counter
+ * @tc:			Pointer to time counter which is to be initialized/reset
+ * @cc:			A cycle counter, ready to be used.
+ * @start_tstamp:	Arbitrary initial time stamp.
+ *
+ * After this call the current cycle register (roughly) corresponds to
+ * the initial time stamp. Every call to timecounter_read() increments
+ * the time stamp counter by the number of elapsed nanoseconds.
+ */
+extern void timecounter_init(struct timecounter *tc,
+			const struct cyclecounter *cc,
+			u64 start_tstamp);
+
+/**
+ * timecounter_read - return nanoseconds elapsed since timecounter_init()
+ *                         plus the initial time stamp
+ * @tc:          Pointer to time counter.
+ *
+ * In other words, keeps track of time since the same epoch as
+ * the function which generated the initial time stamp.
+ */
+extern u64 timecounter_read(struct timecounter *tc);
+
+/**
+ * timecounter_cyc2time - convert a cycle counter to same
+ *                        time base as values returned by
+ *                        timecounter_read()
+ * @tc:		Pointer to time counter.
+ * @cycle:	a value returned by tc->cc->read()
+ *
+ * Cycle counts that are converted correctly as long as they
+ * fall into the interval [-1/2 max cycle count, +1/2 max cycle count],
+ * with "max cycle count" == cs->mask+1.
+ *
+ * This allows conversion of cycle counter values which were generated
+ * in the past.
+ */
+extern u64 timecounter_cyc2time(struct timecounter *tc,
+				cycle_t cycle_tstamp);
+
+/**
  * struct clocksource - hardware abstraction for a free running counter
  *	Provides mostly state-free accessors to the underlying hardware.
+ *	This is the structure used for system time.
  *
  * @name:		ptr to clocksource name
  * @list:		list head for registration
kernel/time/clocksource.c +76 -0

82 lines not on this page · raw message

Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#31 lore raw

PATCH 10/12 igb: access to NIC time

Adds the register definitions and code to read the time register.

---
 drivers/net/igb/e1000_regs.h |   28 +++++++++++
 drivers/net/igb/igb.h        |    4 ++
 drivers/net/igb/igb_main.c   |  106 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 138 insertions(+), 0 deletions(-)
drivers/net/igb/e1000_regs.h +28 -0
index bdf5d83..d225601 100644
@@ -75,6 +75,34 @@
 #define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
 #define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
 #define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+
+/* IEEE 1588 TIMESYNCH */
+#define E1000_TSYNCTXCTL 0x0B614
+#define E1000_TSYNCRXCTL 0x0B620
+#define E1000_TSYNCRXCFG 0x05F50
+
+#define E1000_SYSTIML 0x0B600
+#define E1000_SYSTIMH 0x0B604
+#define E1000_TIMINCA 0x0B608
+
+#define E1000_RXMTRL     0x0B634
+#define E1000_RXSTMPL 0x0B624
+#define E1000_RXSTMPH 0x0B628
+#define E1000_RXSATRL 0x0B62C
+#define E1000_RXSATRH 0x0B630
+
+#define E1000_TXSTMPL 0x0B618
+#define E1000_TXSTMPH 0x0B61C
+
+#define E1000_ETQF0   0x05CB0
+#define E1000_ETQF1   0x05CB4
+#define E1000_ETQF2   0x05CB8
+#define E1000_ETQF3   0x05CBC
+#define E1000_ETQF4   0x05CC0
+#define E1000_ETQF5   0x05CC4
+#define E1000_ETQF6   0x05CC8
+#define E1000_ETQF7   0x05CCC
+
 /* Split and Replication RX Control - RW */
 /*
  * Convenience macros
drivers/net/igb/igb.h +4 -0
index 5a27825..2cf2c1a 100644
@@ -34,6 +34,8 @@
 #include "e1000_mac.h"
 #include "e1000_82575.h"
 
+#include <linux/clocksource.h>
+
 struct igb_adapter;
 
 #ifdef CONFIG_IGB_LRO
@@ -262,6 +264,8 @@ struct igb_adapter {
 	struct napi_struct napi;
 	struct pci_dev *pdev;
 	struct net_device_stats net_stats;
+	struct cyclecounter cycles;
+	struct timecounter clock;
 
 	/* structs defined in e1000_hw.h */
 	struct e1000_hw hw;
drivers/net/igb/igb_main.c +106 -0

124 lines not on this page · raw message

Signature · 6 lines
1.5.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#32 lore raw

PATCH 11/12 time sync: generic infrastructure to map between time stamps generated by a time counter and system time

Currently only mapping from time counter to system time is implemented. The interface could have been made more versatile by not depending on a time counter, but this wasn't done to avoid writing glue code elsewhere.

The method implemented here is the one used and analyzed under the name "assisted PTP" in the LCI PTP paper:
http://www.linuxclustersinstitute.org/conferences/archive/2008/PDF/Ohly_92221.pdf

---
 include/linux/clocksync.h |   85 +++++++++++++++++++
 kernel/time/Makefile      |    2 +-
 kernel/time/clocksync.c   |  196 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 282 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/clocksync.h
 create mode 100644 kernel/time/clocksync.c
include/linux/clocksync.h new file +85 -0
new file mode 100644
index 0000000..d2f93f8
@@ -0,0 +1,85 @@
+/*
+ * Utility code which helps transforming between hardware time stamps
+ * generated by a clocksource and system time. The clocksource is
+ * assumed to return monotonically increasing time (but this code does
+ * its best to compensate if that is not the case) whereas system time
+ * may jump.
+ */
+#ifndef _LINUX_CLOCKSYNC_H
+#define _LINUX_CLOCKSYNC_H
+
+#include <linux/clocksource.h>
+#include <linux/ktime.h>
+
+/**
+ * struct clocksync - stores state and configuration for the two clocks
+ *
+ * Initialize to zero, then set clock, systime, num_samples.
+ *
+ * Transformation between HW time and system time is done with:
+ * HW time transformed = HW time + offset +
+ *                       (HW time - last_update) * skew / CLOCKSYNC_SKEW_RESOLUTION
+ *
+ * @clock:           the source for HW time stamps (%clocksource_read_time)
+ * @systime:         function returning current system time (ktime_get
+ *                   for monotonic time, or ktime_get_real for wall clock)
+ * @num_samples:     number of times that HW time and system time are to
+ *                   be compared when determining their offset
+ * @offset:          (system time - HW time) at the time of the last update
+ * @skew:            average (system time - HW time) / delta HW time *
+ *                   CLOCKSYNC_SKEW_RESOLUTION
+ * @last_update:     last HW time stamp when clock offset was measured
+ */
+struct clocksync {
+	struct timecounter *clock;
+	ktime_t (*systime)(void);
+	int num_samples;
+
+	s64 offset;
+	s64 skew;
+	u64 last_update;
+};
+
+/**
+ * clocksync_hw2sys - transform HW time stamp into corresponding system time
+ * @sync:             context for clock sync
+ * @hwtstamp:         the result of timecounter_read() or
+ *                    timecounter_cyc2time()
+ */
+extern ktime_t clocksync_hw2sys(struct clocksync *sync,
+				u64 hwtstamp);
+
+/**
+ * clocksync_offset - measure current (system time - HW time) offset
+ * @sync:             context for clock sync
+ * @offset:           average offset during sample period returned here
+ * @hwtstamp:         average HW time during sample period returned here
+ *
+ * Returns number of samples used. Might be zero (= no result) in the
+ * unlikely case that system time was monotonically decreasing for all
+ * samples (= broken).
+ */
+extern int clocksync_offset(struct clocksync *sync,
+			s64 *offset,
+			u64 *hwtstamp);
+
+extern void __clocksync_update(struct clocksync *sync,
+			u64 hwtstamp);
+
+/**
+ * clocksync_update - update offset and skew by measuring current offset
+ * @sync:             context for clock sync
+ * @hwtstamp:         the result of timecounter_read() or
+ *                    timecounter_cyc2time(), pass zero to force update
+ *
+ * Updates are only done at most once per second.
+ */
+static inline void clocksync_update(struct clocksync *sync,
+			u64 hwtstamp)
+{
+	if (!hwtstamp ||
+		(s64)(hwtstamp - sync->last_update) >= NSEC_PER_SEC)
+		__clocksync_update(sync, hwtstamp);
+}
+
+#endif /* _LINUX_CLOCKSYNC_H */
kernel/time/Makefile +1 -1
index 905b0b5..6279fb0 100644
@@ -1,4 +1,4 @@
-obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
+obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o clocksync.o
 
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)		+= clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)		+= tick-common.o
kernel/time/clocksync.c new file +196 -0

196 lines not on this page · raw message

Signature · 1 line
1.5.5.3
#33 lore raw

PATCH 12/12 igb: use clocksync to implement hardware time stamping

Both TX and RX hardware time stamping are implemented. Due to hardware limitations it is not possible to verify reliably which packet was time stamped when multiple were pending for sending; this could be solved by only allowing one packet marked for hardware time stamping into the queue (not implemented yet).

RX time stamping relies on the flag in the packet descriptor which marks packets that were time stamped. In "all packet" mode this flag is not set. TODO: also support that mode (even though it'll suffer from race conditions).

Allocation of RX buffers is not optimal yet: the extra space for hardware time stamps is always allocated. Either this should only be done when HW time stamping is (implies reallocation of buffers) or packets with HW time stamps should be copied into a larger buffer (implies higher overhead for those packets).

---
 drivers/net/igb/e1000_82575.h   |    1 +
 drivers/net/igb/e1000_defines.h |    1 +
 drivers/net/igb/e1000_regs.h    |   40 ++++++
 drivers/net/igb/igb.h           |    4 +
 drivers/net/igb/igb_main.c      |  275 +++++++++++++++++++++++++++++++++++++--
 5 files changed, 312 insertions(+), 9 deletions(-)
drivers/net/igb/e1000_82575.h +1 -0
index c1928b5..dd32a6f 100644
@@ -116,6 +116,7 @@ union e1000_adv_tx_desc {
 };
 
 /* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_MAC_TSTAMP   0x00080000 /* IEEE1588 Timestamp packet */
 #define E1000_ADVTXD_DTYP_CTXT    0x00200000 /* Advanced Context Descriptor */
 #define E1000_ADVTXD_DTYP_DATA    0x00300000 /* Advanced Data Descriptor */
 #define E1000_ADVTXD_DCMD_IFCS    0x02000000 /* Insert FCS (Ethernet CRC) */
drivers/net/igb/e1000_defines.h +1 -0
index 40d0342..8909252 100644
@@ -104,6 +104,7 @@
 #define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
 #define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
 #define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_STAT_TS       0x10000 /* Pkt was time stamped */
 #define E1000_RXD_ERR_CE        0x01    /* CRC Error */
 #define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
 #define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
drivers/net/igb/e1000_regs.h +40 -0
index d225601..215d4d6 100644
@@ -78,9 +78,37 @@
 
 /* IEEE 1588 TIMESYNCH */
 #define E1000_TSYNCTXCTL 0x0B614
+#define E1000_TSYNCTXCTL_VALID (1<<0)
+#define E1000_TSYNCTXCTL_ENABLED (1<<4)
 #define E1000_TSYNCRXCTL 0x0B620
+#define E1000_TSYNCRXCTL_VALID (1<<0)
+#define E1000_TSYNCRXCTL_ENABLED (1<<4)
+enum {
+	E1000_TSYNCRXCTL_TYPE_L2_V2 = 0,
+	E1000_TSYNCRXCTL_TYPE_L4_V1 = (1<<1),
+	E1000_TSYNCRXCTL_TYPE_L2_L4_V2 = (1<<2),
+	E1000_TSYNCRXCTL_TYPE_ALL = (1<<3),
+	E1000_TSYNCRXCTL_TYPE_EVENT_V2 = (1<<3) | (1<<1),
+};
 #define E1000_TSYNCRXCFG 0x05F50
+enum {
+	E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE = 0<<0,
+	E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE = 1<<0,
+	E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE = 2<<0,
+	E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE = 3<<0,
+	E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE = 4<<0,
 
+	E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE = 0<<8,
+	E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE = 1<<8,
+	E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE = 2<<8,
+	E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE = 3<<8,
+	E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE = 8<<8,
+	E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE = 9<<8,
+	E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE = 0xA<<8,
+	E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE = 0xB<<8,
+	E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE = 0xC<<8,
+	E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE = 0xD<<8,
+};
 #define E1000_SYSTIML 0x0B600
 #define E1000_SYSTIMH 0x0B604
 #define E1000_TIMINCA 0x0B608
@@ -103,6 +131,18 @@
 #define E1000_ETQF6   0x05CC8
 #define E1000_ETQF7   0x05CCC
 
+/* Filtering Registers */
+#define E1000_SAQF(_n) (0x5980 + 4 * (_n))
+#define E1000_DAQF(_n) (0x59A0 + 4 * (_n))
+#define E1000_SPQF(_n) (0x59C0 + 4 * (_n))
+#define E1000_FTQF(_n) (0x59E0 + 4 * (_n))
+#define E1000_SAQF0 E1000_SAQF(0)
+#define E1000_DAQF0 E1000_DAQF(0)
+#define E1000_SPQF0 E1000_SPQF(0)
+#define E1000_FTQF0 E1000_FTQF(0)
+#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
+#define E1000_ETQF(_n)  (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
+
 /* Split and Replication RX Control - RW */
 /*
  * Convenience macros
drivers/net/igb/igb.h +4 -0
index 2cf2c1a..9972801 100644
@@ -35,6 +35,8 @@
 #include "e1000_82575.h"
 
 #include <linux/clocksource.h>
+#include <linux/clocksync.h>
+#include <linux/net_tstamp.h>
 
 struct igb_adapter;
 
@@ -266,6 +268,8 @@ struct igb_adapter {
 	struct net_device_stats net_stats;
 	struct cyclecounter cycles;
 	struct timecounter clock;
+	struct clocksync sync;
+	struct hwtstamp_config hwtstamp_config;
 
 	/* structs defined in e1000_hw.h */
 	struct e1000_hw hw;
drivers/net/igb/igb_main.c +266 -9

359 lines not on this page · raw message

Signature · 1 line
1.5.5.3
#34 lore raw

Re: [PATCH NET-NEXT 11/12] time sync: generic infrastructure to map between time stamps generated by a time counter and system time

In reply to Patrick Ohly
Quoted 7 lines · Patrick Ohly

Currently only mapping from time counter to system time is implemented. The interface could have been made more versatile by not depending on a time counter, but this wasn't done to avoid writing glue code elsewhere.

The method implemented here is the one used and analyzed under the name "assisted PTP" in the LCI PTP paper:
http://www.linuxclustersinstitute.org/conferences/archive/2008/PDF/Ohly_92221.pdf

Quoted 7 lines
---
 include/linux/clocksync.h |   85 +++++++++++++++++++
 kernel/time/Makefile      |    2 +-
 kernel/time/clocksync.c   |  196 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 282 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/clocksync.h
 create mode 100644 kernel/time/clocksync.c

hm, these bits have less than casual impact - i think they need to go via the timer tree.

Ingo
--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#35 lore raw

Re: [PATCH NET-NEXT 11/12] time sync: generic infrastructure to map between time stamps generated by a time counter and system time

Quoted 17 lines · Ingo Molnar
Quoted 7 lines · Patrick Ohly

Currently only mapping from time counter to system time is implemented. The interface could have been made more versatile by not depending on a time counter, but this wasn't done to avoid writing glue code elsewhere.

The method implemented here is the one used and analyzed under the name "assisted PTP" in the LCI PTP paper:
http://www.linuxclustersinstitute.org/conferences/archive/2008/PDF/Ohly_92221.pdf

Quoted 7 lines
---
 include/linux/clocksync.h |   85 +++++++++++++++++++
 kernel/time/Makefile      |    2 +-
 kernel/time/clocksync.c   |  196 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 282 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/clocksync.h
 create mode 100644 kernel/time/clocksync.c
Quoted 2 lines

hm, these bits have less than casual impact - i think they need to go via the timer tree.

I agree that they should be reviewed by experts in that area. Patch 11 and 09 (which 11 depends on and which was already reviewed by John) are independent of the rest of the patch series and could be included in the timer tree. On the other hand that code is only called by the example igb driver in this patch series, which won't compile without the timer changes.

Please let me know if I should pursue the inclusion separately and if so, how the inclusion of the two trees can be coordinated.

Signature · 6 lines
Best Regards, Patrick Ohly

The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.
maintainer
#36 lore raw
In reply to Patrick Ohly

From: Patrick Ohly <[email protected]>
Date: Wed, 21 Jan 2009 11:07:37 +0100

Quoted 8 lines

I tested them with the modified PTPd with and without hardware support on x86. With 64 bit kernel and user space both works. With 32 bit user space on a 64 bit kernel software-only time stamping works (thanks to the socket's compatibility layer), hardware support doesn't: the ifreq is passed to the right device driver, but the data pointer from a 32 bit process is not interpreted correctly by a 64 bit driver. If there is a way to handle this then please let me know - I didn't see how a device driver could distinguish between a 32 and 64 bit user process.

See fs/compat_ioctl.c:dev_ifsioc() for how to handle the "32-bit process under 64-bit kernel" issue wrt. struct ifreq

Next, I don't like that loop in the SKB allocator to deal with the variable size. You're computing what amounts to a constant calculation.

Just consolidate the array into a direct conversion table. You only have 2 bits defined so you only need an array of 4 entries. Pass the optional flag bits directly in as the index of that table.

#37 lore raw
Quoted 4 lines · David Miller

From: Patrick Ohly <[email protected]>
Date: Wed, 21 Jan 2009 11:07:37 +0100
See fs/compat_ioctl.c:dev_ifsioc() for how to handle the "32-bit process under 64-bit kernel" issue wrt. struct ifreq

Thanks, will do.

Quoted 3 lines

Just consolidate the array into a direct conversion table. You only have 2 bits defined so you only need an array of 4 entries. Pass the optional flag bits directly in as the index of that table.

How can I get some code executed during the initialization of the IP stack which initializes the table, before any sk_buff gets allocated?

The content is constant, but writing it down as static initializers using just preprocessor macros would be difficult and/or ugly - that's why I haven't done it already.

Bye, Patrick

maintainer
#38 lore raw

From: Patrick Ohly <[email protected]>
Date: Mon, 26 Jan 2009 21:39:52 +0100

Quoted 11 lines · David Miller
Quoted 3 lines

Just consolidate the array into a direct conversion table. You only have 2 bits defined so you only need an array of 4 entries. Pass the optional flag bits directly in as the index of that table.

How can I get some code executed during the initialization of the IP stack which initializes the table, before any sk_buff gets allocated?

The content is constant, but writing it down as static initializers using just preprocessor macros would be difficult and/or ugly - that's why I haven't done it already.

It's 4 entries... really. You can initialize them simply, perhaps with some fancy macro used by the initializers.
--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#39 lore raw
Quoted 8 lines · David Miller

From: Patrick Ohly <[email protected]>
Date: Mon, 26 Jan 2009 21:39:52 +0100

Quoted 5 lines · David Miller
Quoted 3 lines

Just consolidate the array into a direct conversion table. You only have 2 bits defined so you only need an array of 4 entries. Pass the optional flag bits directly in as the index of that table.

Quoted 8 lines
Quoted 6 lines

How can I get some code executed during the initialization of the IP stack which initializes the table, before any sk_buff gets allocated?

The content is constant, but writing it down as static initializers using just preprocessor macros would be difficult and/or ugly - that's why I haven't done it already.

It's 4 entries... really.

True - at this time. But what if this extension mechanism turns out to be useful and we end up with more optional structures? I was hoping that this might be the case and thus tried to make it easy to add more structures.

Quoted 2 lines

You can initialize them simply, perhaps
with some fancy macro used by the initializers.

Unfortunately recursion in macros is not possible. One needs duplicated macro definitions, one for each additional structure. But perhaps my preprocessor code fu is lacking today and there is a simpler solution :-/

Anyway, below is example code with three structures which initializes a size array indexed by a bit mask. I find it truly ugly and hard to understand - and I wrote it. gcc -S shows that the size arrays contain the expected values.

Please let me know what approach is preferred and I'll revise the patch accordingly:
1. array with four hard-coded values
2. init code (where?)
3. macro initialization of array
4. simpler initialization solution

---------------------------------------------------------------

struct A {
    int a;
};
struct B {
    char b;
};
struct C {
    long long c;
};
enum {
    BIT_A,
    BIT_B,
    BIT_C
};

#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))

/* round up _previous number of bytes so that a struct of_structsize
bytes is properly aligned at an 8 byte boundary or the structure size, whatever is smaller */

#define ALIGN(_previous, _structsize) \
    (((_previous) + MIN(_structsize, 8) - 1) & ~(MIN(_structsize, 8) - 1))

/* number of bytes for struct X alone
* @_flags: bit mask of BIT_ values
* @_bitname: name of bit enum for X
* @_structname: structure name of X, without struct */

#define SIZE_X(_flags, _bitname, _structname) \
    (((_flags) & (1<<_bitname)) ? sizeof(struct _structname) : 0)

/* number of bytes needed for B (if present) with or without A in
* front of it
* @_flags: bit mask of BIT_A and BIT_B
*/

#define SIZE_B(_flags) \
    (((_flags) & (1<<BIT_B)) ? \
     (ALIGN(SIZE_X(_flags, BIT_A, A), SIZE_X(_flags, BIT_B, B)) + sizeof(struct B)) : \
     SIZE_X(_flags, BIT_A, A))

/* number of bytes needed for C (if present) with combinations of
* struct A, B in front
* @_flags: bit mask of BIT_A, BIT_B, BIT_C
*/

#define SIZE_C(_flags) \
    (((_flags) & (1<<BIT_C)) ? \
     (ALIGN(SIZE_B(_flags), SIZE_X(_flags, BIT_C, C)) + sizeof(struct C)) : \
     SIZE_B(_flags))

/* number of bytes needed to store combinations of A, B, C, in this
order */
int size[] = { 0,

               SIZE_X((1<<BIT_A), BIT_A, A),

               SIZE_B((1<<BIT_B)),
               SIZE_B((1<<BIT_B)|(1<<BIT_A)),

               SIZE_C((1<<BIT_C)),
               SIZE_C((1<<BIT_C)|(1<<BIT_A)),
               SIZE_C((1<<BIT_C)|(1<<BIT_B)),
               SIZE_C((1<<BIT_C)|(1<<BIT_B)|(1<<BIT_A)) };
#define LIST_A(_flags) SIZE_C(_flags), SIZE_C((_flags)|(1<<BIT_A))
#define LIST_B(_flags) LIST_A(_flags), LIST_A((_flags)|(1<<BIT_B))
#define LIST_C(_flags) LIST_B(_flags), LIST_B((_flags)|(1<<BIT_C))

/* same as size */
int size2[] = { LIST_C(0) };
---------------------------------------------------------------

Bye, Patrick

#40 lore raw
Quoted 5 lines · Patrick Ohly

True - at this time. But what if this extension mechanism turns out to be useful and we end up with more optional structures? I was hoping that this might be the case and thus tried to make it easy to add more structures.

You're putting the extension in the skb->end area, right?

How big are the time stamps? If they're not that big, why don't we put it into the shinfo structure itself? For the common case, we have plenty of space due to kmalloc padding anyway.

Cheers,

Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#41 lore raw
Quoted 8 lines · Herbert Xu
Quoted 5 lines · Patrick Ohly

True - at this time. But what if this extension mechanism turns out to be useful and we end up with more optional structures? I was hoping that this might be the case and thus tried to make it easy to add more structures.

You're putting the extension in the skb->end area, right?

Right.

Quoted 3 lines

How big are the time stamps? If they're not that big, why don't we put it into the shinfo structure itself? For the common case, we have plenty of space due to kmalloc padding anyway.

Two 64 bit fields have to be added for time stamps plus 3 bits for flags (for time stamping instructions, currently in skb_shared_tx).

Putting that into shinfo should work fine. I thought extending that structure with information that isn't needed for all packets was as bad as extending sk_buff itself. If that isn't the case, then extending shinfo definitely is the simplest solution.

Bye, Patrick

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#42 lore raw
Quoted 5 lines · Patrick Ohly

Putting that into shinfo should work fine. I thought extending that structure with information that isn't needed for all packets was as bad as extending sk_buff itself. If that isn't the case, then extending shinfo definitely is the simplest solution.

Not at all, the sk_buff has its own slab while skb->head uses kmalloc. The latter has loads of free space due to padding for common MTUs such as 1500 or header-only.

Cheers,

Signature · 8 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
maintainer
#43 lore raw
In reply to Herbert Xu

From: Herbert Xu <[email protected]>
Date: Wed, 28 Jan 2009 20:08:21 +1100

Quoted 7 lines
Quoted 5 lines · Patrick Ohly

True - at this time. But what if this extension mechanism turns out to be useful and we end up with more optional structures? I was hoping that this might be the case and thus tried to make it easy to add more structures.

Quoted 5 lines

You're putting the extension in the skb->end area, right?

How big are the time stamps? If they're not that big, why don't we put it into the shinfo structure itself? For the common case, we have plenty of space due to kmalloc padding anyway.

I did some thinking about this, and for the time being I think we should stick all of these new pieces of timestamp information in the skb shared info structure and unconditionally.

Use unions where possible, but besides that don't try to be clever at all. We'll try to optimize this later.

So you can therefore get rid of all of this conditional sizing and other complexity, which is distracting from what the patch is actually doing. As a result I expect patch #2 to shrink to basically nothing :) Patch #4 should also become unnecessary, etc. etc.

Other than that, I went over the patches again, and here is some other feedback:

1) Please kill the SO_TIMESTAMPING/SCM_TIMESTAMPING/SIOCHWTSTAMP fallback definition in linux/net_tstamp.h

We don't do things like that. The SIOCHWTSTAMP one was using __kernel__ (lowercase) instead of __KERNEL__ so it wouldn't work anyways :-)

2) Please fix up some coding style issues. For example, when you have a multiline conditional as you do in sock_recv_timestamp(), format it like this:

	if (a ||
	    b ||
	    c)

instead of the two tab thing you're doing on the lines after the first one in the conditional. There are many cases of this, so please go over all of your patches and review for this.

The sock_tx_timestamp() declaration has similar issues. Make the arguments on the subsequent lines start right after the openning parenthesis on the first line.

Please don't use braces for a basic block composed of only one line, it's just wasted space, for example:

	if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) {
		shtx->hardware = 1;
	}

should be just:

	if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE))
		shtx->hardware = 1;

I could go on and on, but that's pointless, just read Documentation/CodingStyle and use checkpatch.pl output as a further guide.

3) In the debug check added by patch #6 please use a construct such as WARN_ON() or WARN_ON_ONCE(), it can even be embedded in a conditional.

4) Please get patches #9 and #11 on a fresh review on linux-kernel with the timer maintainers CC:'d. Once they ACK, get a figure on how we can arrange the merge of these changes.

Just like you I think we have to merge this in via the net tree since the only user we have is this hwtstamp networking stuff. So please express that and try to get the timer folk's blessing on that.

5) Finally, try to put the driver patches at the end so that they finish the patch series and the driver maintainer ACK'ing can be handled seperately and won't hold up the infrastructure patches.

Otherwise this stuff looks good, please keep working on this stuff! --
To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#44 lore raw
Quoted 10 lines · David Miller

From: Herbert Xu <[email protected]>
Date: Wed, 28 Jan 2009 20:08:21 +1100

Quoted 3 lines

How big are the time stamps? If they're not that big, why don't we put it into the shinfo structure itself? For the common case, we have plenty of space due to kmalloc padding anyway.

I did some thinking about this, and for the time being I think we should stick all of these new pieces of timestamp information in the skb shared info structure and unconditionally.

Agreed. I have changed the code accordingly. As expected it became considerably simpler.

I also fixed the 32 bit on 64 bit kernel issue with the SIOCSHWTSTAMP ioctl.

Quoted 3 lines

So you can therefore get rid of all of this conditional sizing and other complexity, which is distracting from what the patch is actually doing. As a result I expect patch #2 to shrink to basically nothing :)

I kept the struct/union definition around because in some places the information needs to be stored detached from skb_shared_info. I also kept the accessor functions because that way the code using the information is better separated from how the information is stored.

The only change in these accessors is that they are now guaranteed to never return NULL; code using them was simplified accordingly.

Quoted 9 lines

Other than that, I went over the patches again, and here is some other feedback:

1) Please kill the SO_TIMESTAMPING/SCM_TIMESTAMPING/SIOCHWTSTAMP fallback definition in linux/net_tstamp.h

We don't do things like that. The SIOCHWTSTAMP one was using __kernel__ (lowercase) instead of __KERNEL__ so it wouldn't work anyways :-)

Okay. I moved that into the timestamping.c example. Such a fallback is needed in user space programs because the latest kernel's header files might not be installed yet: net_tstamp.h is found, platform specific asm-* files are not. Instead files from /usr/include are picked up.

Quoted 8 lines

2) Please fix up some coding style issues. For example, when you have a multiline conditional as you do in sock_recv_timestamp(), format it like this:

        if (a ||
            b ||
            c)
Quoted 7 lines

instead of the two tab thing you're doing on the lines after the first one in the conditional. There are many cases of this, so please go over all of your patches and review for this.

The sock_tx_timestamp() declaration has similar issues. Make the arguments on the subsequent lines start right after the openning parenthesis on the first line.

I didn't find anything about this aspect of line continuation in the CodingStyle, so I used the emacs configuration given there and relied on it to do the formatting correctly. That's no excuse of course, just an explanation. It looked wrong, but so does much of the other Linux kernel code to my unaccustomed eyes ;-)

Does anyone have an improved version of the emacs macros or is this something that has to be formatted manually? For now I'm fixing it manually.

I hope I'm catching all of it; checkpatch.pl doesn't warn about it.

Quoted 6 lines

Please don't use braces for a basic block composed of only one
line, it's just wasted space, for example:

        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) {
                shtx->hardware = 1;
        }

Right. I fixed some of those already, but missed that one.

I went through all patches and fixed all the checkstack.pl reports, except for some warnings about long lines that I preferred not to split (usually string constants).

Quoted 8 lines

4) Please get patches #9 and #11 on a fresh review on linux-kernel with the timer maintainers CC:'d. Once they ACK, get a figure on how we can arrange the merge of these changes.

Just like you I think we have to merge this in via the net tree since the only user we have is this hwtstamp networking stuff. So please express that and try to get the timer folk's blessing on that.

Okay.

Quoted 3 lines

5) Finally, try to put the driver patches at the end so that they finish the patch series and the driver maintainer ACK'ing can be handled seperately and won't hold up the infrastructure patches.

Okay. John Ronciak already expressed an interest in reviewing them. I'll discuss with him and other Intel igb maintainers before posting the patch series again.

Quoted 1 line

Otherwise this stuff looks good, please keep working on this stuff!

Glad to hear there. I'll do my best to finish this. It's quite an experience ;-)

Signature · 6 lines
Best Regards, Patrick Ohly

The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.