linux-can.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Oliver Hartkopp <socketcan@hartkopp.net>
To: Stephane Grosjean <s.grosjean@peak-system.com>
Cc: "linux-can@vger.kernel.org" <linux-can@vger.kernel.org>
Subject: Re: About timestamping and can-utils
Date: Thu, 06 Mar 2014 10:56:17 +0100	[thread overview]
Message-ID: <53184641.1040506@hartkopp.net> (raw)
In-Reply-To: <53183F0E.7050309@peak-system.com>

[-- Attachment #1: Type: text/plain, Size: 1976 bytes --]

Hi Stephane,

here's a discussion thread from last year focussing HW timestamping:

http://marc.info/?l=linux-can&m=138210737431112&w=2

Additionally I attached two patches:

cants-test.patch:
added some functionality to add a monotonic (sw) timestamp to sja1000

candump-hwts.patch:
added some functionality to candump to get these timestamps

The candump patch is from the time before the include file cleanup inside the
can-utils provided by Uwe. (including from socketcan directory)

Together with the discussion thread from above, this should give a good
starting point.

Regards,
Oliver


On 06.03.2014 10:25, Stephane Grosjean wrote:
> Hi linux-can team,
> 
> I've got one question about how timestamping is done now in linux-can,
> regarding to HW timestamps.
> 
> In the early ages (~v3.4), the CAN hardware driver could set the timestamp of
> an skb by itself and push it with the received CAN frame, so that the
> application could get it using SO_TIMESTAMP socket option, right?
> Now, this "hardware" timestamp is to be copied into "hwstamp" field of the
> "skb_hwtstamps(skb)" area.
> 
> But how does user application manage to get this hardware timestamp on its
> side? AFAIK, the "candump" can-utils utility always reads and displays the
> "network" timestamp (that is, always uses SO_TIMESTAMP socket option). I had a
> quick look to the Kernel sources and tried to find the links between things
> but it's not very clear to me: first idea I tested was to set the
> SO_TIMESTAMPING socket option, but candump never received any hw timestamp in
> the control messages he reads from the CAN socket...
> 
> Any help would be appreciated.
> 
> Regards,
> 
> Stéphane
> -- 
> PEAK-System Technik GmbH, Otto-Roehm-Strasse 69, D-64293 Darmstadt
> Geschaeftsleitung: A.Gach/U.Wilhelm,St.Nr.:007/241/13586 FA Darmstadt HRB-9183
> Darmstadt, Ust.IdNr.:DE 202220078, WEE-Reg.-Nr.: DE39305391 Tel.+49
> (0)6151-817320 / Fax:+49 (0)6151-817329, info@peak-system.com
> -- 

[-- Attachment #2: cants-test.patch --]
[-- Type: text/x-diff, Size: 1529 bytes --]

diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 7164a99..57b5d44 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -326,6 +326,8 @@ static void sja1000_rx(struct net_device *dev)
 	struct net_device_stats *stats = &dev->stats;
 	struct can_frame *cf;
 	struct sk_buff *skb;
+	struct timespec tsraw, tsreal;
+	struct skb_shared_hwtstamps *hwts;
 	uint8_t fi;
 	uint8_t dreg;
 	canid_t id;
@@ -366,6 +368,11 @@ static void sja1000_rx(struct net_device *dev)
 	/* release receive buffer */
 	sja1000_write_cmdreg(priv, CMD_RRB);
 
+	getnstime_raw_and_real(&tsraw, &tsreal);
+	skb->tstamp = timespec_to_ktime(tsreal);
+	hwts = skb_hwtstamps(skb);
+	hwts->syststamp = timespec_to_ktime(tsraw);
+
 	netif_rx(skb);
 
 	stats->rx_packets++;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 947ba25..19fc013 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -431,8 +431,6 @@ ktime_t ktime_get_clocktai(void)
 }
 EXPORT_SYMBOL(ktime_get_clocktai);
 
-#ifdef CONFIG_NTP_PPS
-
 /**
  * getnstime_raw_and_real - get day and raw monotonic time in timespec format
  * @ts_raw:	pointer to the timespec to be set to raw monotonic time
@@ -467,8 +465,6 @@ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
 }
 EXPORT_SYMBOL(getnstime_raw_and_real);
 
-#endif /* CONFIG_NTP_PPS */
-
 /**
  * do_gettimeofday - Returns the time of day in a timeval
  * @tv:		pointer to the timeval to be set

[-- Attachment #3: candump-hwts.patch --]
[-- Type: text/x-diff, Size: 9658 bytes --]

diff --git a/Makefile b/Makefile
index 2f79ee7..40067fb 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ MAKEFLAGS = -k
 
 CFLAGS    = -O2 -Wall -Wno-parentheses -Iinclude \
 	    -fno-strict-aliasing \
+	    -DSO_TIMESTAMPING=37 \
 	    -DSO_RXQ_OVFL=40 \
 	    -DPF_CAN=29 \
 	    -DAF_CAN=PF_CAN
diff --git a/candump.c b/candump.c
index c865bd7..d7723d8 100644
--- a/candump.c
+++ b/candump.c
@@ -60,6 +60,7 @@
 
 #include <linux/can.h>
 #include <linux/can/raw.h>
+#include <linux/net_tstamp.h>
 
 #include "terminal.h"
 #include "lib.h"
@@ -106,7 +107,8 @@ void print_usage(char *prg)
 {
 	fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
 	fprintf(stderr, "  (use CTRL-C to terminate %s)\n\n", prg);
-	fprintf(stderr, "Options: -t <type>   (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
+	fprintf(stderr, "Options: -t <type>   (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date )\n");
+	fprintf(stderr, "                     (           (r)aw hardware/(s)ystem hardware transformed)\n");
 	fprintf(stderr, "         -c          (increment color mode level)\n");
 	fprintf(stderr, "         -i          (binary output - may exceed 80 chars/line)\n");
 	fprintf(stderr, "         -a          (enable additional ASCII output)\n");
@@ -219,7 +221,10 @@ int main(int argc, char **argv)
 	int currmax, numfilter;
 	char *ptr, *nptr;
 	struct sockaddr_can addr;
-	char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
+	struct {
+		struct cmsghdr cm;
+		char control[512];
+	} control;
 	struct iovec iov;
 	struct msghdr msg;
 	struct cmsghdr *cmsg;
@@ -228,7 +233,8 @@ int main(int argc, char **argv)
 	struct canfd_frame frame;
 	int nbytes, i, maxdlen;
 	struct ifreq ifr;
-	struct timeval tv, last_tv;
+	struct timespec *stamp;
+	static struct timeval tv, last_tv;
 	struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
 	FILE *logfile = NULL;
 
@@ -244,6 +250,7 @@ int main(int argc, char **argv)
 		case 't':
 			timestamp = optarg[0];
 			if ((timestamp != 'a') && (timestamp != 'A') &&
+			    (timestamp != 'r') && (timestamp != 's') &&
 			    (timestamp != 'd') && (timestamp != 'z')) {
 				fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n",
 				       basename(argv[0]), optarg[0]);
@@ -537,12 +544,30 @@ int main(int argc, char **argv)
 
 		if (timestamp || log || logfrmt) {
 
-			const int timestamp_on = 1;
+			if ((timestamp != 'r') && (timestamp != 's')) {
 
-			if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
-				       &timestamp_on, sizeof(timestamp_on)) < 0) {
-				perror("setsockopt SO_TIMESTAMP");
-				return 1;
+				const int timestamp_on = 1;
+
+				if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
+					       &timestamp_on, sizeof(timestamp_on)) < 0) {
+					perror("setsockopt SO_TIMESTAMP");
+					return 1;
+				}
+			} else {
+
+//				int timestamping_flags = (SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_HARDWARE);
+				int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_HARDWARE);
+
+				if (timestamp == 'r')
+					timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
+				else
+					timestamping_flags |= SOF_TIMESTAMPING_SYS_HARDWARE;
+
+				if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
+					       &timestamping_flags, sizeof(timestamping_flags)) < 0) {
+					perror("setsockopt SO_TIMESTAMPING");
+					return 1;
+				}
 			}
 		}
 
@@ -600,7 +625,7 @@ int main(int argc, char **argv)
 	msg.msg_name = &addr;
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
-	msg.msg_control = &ctrlmsg;
+	msg.msg_control = &control;
 
 	while (running) {
 
@@ -626,7 +651,7 @@ int main(int argc, char **argv)
 				/* these settings may be modified by recvmsg() */
 				iov.iov_len = sizeof(frame);
 				msg.msg_namelen = sizeof(addr);
-				msg.msg_controllen = sizeof(ctrlmsg);  
+				msg.msg_controllen = sizeof(control);
 				msg.msg_flags = 0;
 
 				nbytes = recvmsg(s[i], &msg, 0);
@@ -664,10 +689,48 @@ int main(int argc, char **argv)
 				for (cmsg = CMSG_FIRSTHDR(&msg);
 				     cmsg && (cmsg->cmsg_level == SOL_SOCKET);
 				     cmsg = CMSG_NXTHDR(&msg,cmsg)) {
-					if (cmsg->cmsg_type == SO_TIMESTAMP)
+
+					switch (cmsg->cmsg_type) {
+
+					case SO_TIMESTAMP:
+						printf("SO_TIMESTAMP\n");
 						tv = *(struct timeval *)CMSG_DATA(cmsg);
-					else if (cmsg->cmsg_type == SO_RXQ_OVFL)
+						break;
+
+					case SO_TIMESTAMPING:
+						stamp = (struct timespec *)CMSG_DATA(cmsg);
+						printf("SO_TIMESTAMPING\n");
+
+						if (timestamp == 'r') {
+							tv.tv_sec = (stamp + 2)->tv_sec;
+							tv.tv_usec = (stamp + 2)->tv_nsec/1000;
+						} else {
+							tv.tv_sec = (stamp + 1)->tv_sec;
+							tv.tv_usec = (stamp + 1)->tv_nsec/1000;
+						}
+
+						printf("SW %lu.%09lu ",
+						       (long)stamp->tv_sec,
+						       (long)stamp->tv_nsec);
+						stamp++;
+						printf("HW transformed %lu.%09lu ",
+						       (long)stamp->tv_sec,
+						       (long)stamp->tv_nsec);
+						stamp++;
+						printf("HW raw %lu.%09lu",
+						       (long)stamp->tv_sec,
+						       (long)stamp->tv_nsec);
+						printf("\n");
+						break;
+
+					case SO_RXQ_OVFL:
+						printf("SO_RXQ_OVFL\n");
 						dropcnt[i] = *(__u32 *)CMSG_DATA(cmsg);
+						break;
+
+					default:
+						printf("unknown cmsg_type = %d\n", cmsg->cmsg_type);
+					}
 				}
 
 				/* check for (unlikely) dropped frames on this specific socket */
@@ -726,6 +789,8 @@ int main(int argc, char **argv)
 				switch (timestamp) {
 
 				case 'a': /* absolute with timestamp */
+				case 'r': /* absolute with raw hardware timestamp */
+				case 's': /* absolute with system hardware transformed timestamp */
 					printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec);
 					break;
 
diff --git a/include/linux/net_tstamp.h b/include/linux/net_tstamp.h
index e69de29..a8724a7 100644
--- a/include/linux/net_tstamp.h
+++ b/include/linux/net_tstamp.h
@@ -0,0 +1 @@
+#include <socketcan/net_tstamp.h>
diff --git a/include/socketcan/net_tstamp.h b/include/socketcan/net_tstamp.h
index e69de29..ae5df12 100644
--- a/include/socketcan/net_tstamp.h
+++ b/include/socketcan/net_tstamp.h
@@ -0,0 +1,113 @@
+/*
+ * Userspace API for hardware time stamping of network packets
+ *
+ * Copyright (C) 2008,2009 Intel Corporation
+ * Author: Patrick Ohly <patrick.ohly@intel.com>
+ *
+ */
+
+#ifndef _NET_TIMESTAMPING_H
+#define _NET_TIMESTAMPING_H
+
+#include <linux/socket.h>   /* for SO_TIMESTAMPING */
+
+/* SO_TIMESTAMPING gets an integer bit field comprised of these values */
+enum {
+	SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
+	SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1),
+	SOF_TIMESTAMPING_RX_HARDWARE = (1<<2),
+	SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3),
+	SOF_TIMESTAMPING_SOFTWARE = (1<<4),
+	SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5),
+	SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6),
+	SOF_TIMESTAMPING_MASK =
+	(SOF_TIMESTAMPING_RAW_HARDWARE - 1) |
+	SOF_TIMESTAMPING_RAW_HARDWARE
+};
+
+/**
+ * struct hwtstamp_config - %SIOCSHWTSTAMP parameter
+ *
+ * @flags:	no flags defined right now, must be zero
+ * @tx_type:	one of HWTSTAMP_TX_*
+ * @rx_type:	one of one of HWTSTAMP_FILTER_*
+ *
+ * %SIOCSHWTSTAMP expects a &struct ifreq with a ifr_data pointer to
+ * this structure. dev_ifsioc() in the kernel takes care of the
+ * translation between 32 bit userspace and 64 bit kernel. The
+ * structure is intentionally chosen so that it has the same layout on
+ * 32 and 64 bit systems, don't break this!
+ */
+struct hwtstamp_config {
+	int flags;
+	int tx_type;
+	int rx_filter;
+};
+
+/* possible values for hwtstamp_config->tx_type */
+enum hwtstamp_tx_types {
+	/*
+	 * 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,
+
+	/*
+	 * Enables time stamping for outgoing packets just as
+	 * HWTSTAMP_TX_ON does, but also enables time stamp insertion
+	 * directly into Sync packets. In this case, transmitted Sync
+	 * packets will not received a time stamp via the socket error
+	 * queue.
+	 */
+	HWTSTAMP_TX_ONESTEP_SYNC,
+};
+
+/* possible values for hwtstamp_config->rx_filter */
+enum hwtstamp_rx_filters {
+	/* 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,
+	/* PTP v1, UDP, Sync packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_SYNC,
+	/* PTP v1, UDP, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ,
+	/* PTP v2, UDP, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_EVENT,
+	/* PTP v2, UDP, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_SYNC,
+	/* PTP v2, UDP, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ,
+
+	/* 802.AS1, Ethernet, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_EVENT,
+	/* 802.AS1, Ethernet, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_SYNC,
+	/* 802.AS1, Ethernet, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ,
+
+	/* PTP v2/802.AS1, any layer, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_EVENT,
+	/* PTP v2/802.AS1, any layer, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_SYNC,
+	/* PTP v2/802.AS1, any layer, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_DELAY_REQ,
+};
+
+#endif /* _NET_TIMESTAMPING_H */

  reply	other threads:[~2014-03-06  9:56 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-06  9:25 About timestamping and can-utils Stephane Grosjean
2014-03-06  9:56 ` Oliver Hartkopp [this message]
2014-03-06 11:03   ` Stephane Grosjean
2014-03-06 18:47     ` Oliver Hartkopp

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=53184641.1040506@hartkopp.net \
    --to=socketcan@hartkopp.net \
    --cc=linux-can@vger.kernel.org \
    --cc=s.grosjean@peak-system.com \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).