Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ptp: Add PTP_SYS_OFFSET_PRECISE for driver crosstimestamping

Currently, network /system cross-timestamping is performed in the
PTP_SYS_OFFSET ioctl. The PTP clock driver reads gettimeofday() and
the gettime64() callback provided by the driver. The cross-timestamp
is best effort where the latency between the capture of system time
(getnstimeofday()) and the device time (driver callback) may be
significant.

The getcrosststamp() callback and corresponding PTP_SYS_OFFSET_PRECISE
ioctl allows the driver to perform this device/system correlation when
for example cross timestamp hardware is available. Modern Intel
systems can do this for onboard Ethernet controllers using the ART
counter. There is virtually zero latency between captures of the ART
and network device clock.

The capabilities ioctl (PTP_CLOCK_GETCAPS), is augmented allowing
applications to query whether or not drivers implement the
getcrosststamp callback, providing more precise cross timestamping.

Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: kevin.b.stanton@intel.com
Cc: kevin.j.clarke@intel.com
Cc: hpa@zytor.com
Cc: jeffrey.t.kirsher@intel.com
Cc: netdev@vger.kernel.org
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Christopher S. Hall <christopher.s.hall@intel.com>
[jstultz: Commit subject tweaks]
Signed-off-by: John Stultz <john.stultz@linaro.org>

authored by

Christopher S. Hall and committed by
John Stultz
719f1aa4 f9677e0f

+51 -3
+4 -2
Documentation/ptp/testptp.c
··· 277 277 " %d external time stamp channels\n" 278 278 " %d programmable periodic signals\n" 279 279 " %d pulse per second\n" 280 - " %d programmable pins\n", 280 + " %d programmable pins\n" 281 + " %d cross timestamping\n", 281 282 caps.max_adj, 282 283 caps.n_alarm, 283 284 caps.n_ext_ts, 284 285 caps.n_per_out, 285 286 caps.pps, 286 - caps.n_pins); 287 + caps.n_pins, 288 + caps.cross_timestamping); 287 289 } 288 290 } 289 291
+27
drivers/ptp/ptp_chardev.c
··· 22 22 #include <linux/poll.h> 23 23 #include <linux/sched.h> 24 24 #include <linux/slab.h> 25 + #include <linux/timekeeping.h> 25 26 26 27 #include "ptp_private.h" 27 28 ··· 121 120 struct ptp_clock_caps caps; 122 121 struct ptp_clock_request req; 123 122 struct ptp_sys_offset *sysoff = NULL; 123 + struct ptp_sys_offset_precise precise_offset; 124 124 struct ptp_pin_desc pd; 125 125 struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 126 126 struct ptp_clock_info *ops = ptp->info; 127 127 struct ptp_clock_time *pct; 128 128 struct timespec64 ts; 129 + struct system_device_crosststamp xtstamp; 129 130 int enable, err = 0; 130 131 unsigned int i, pin_index; 131 132 ··· 141 138 caps.n_per_out = ptp->info->n_per_out; 142 139 caps.pps = ptp->info->pps; 143 140 caps.n_pins = ptp->info->n_pins; 141 + caps.cross_timestamping = ptp->info->getcrosststamp != NULL; 144 142 if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) 145 143 err = -EFAULT; 146 144 break; ··· 182 178 req.type = PTP_CLK_REQ_PPS; 183 179 enable = arg ? 1 : 0; 184 180 err = ops->enable(ops, &req, enable); 181 + break; 182 + 183 + case PTP_SYS_OFFSET_PRECISE: 184 + if (!ptp->info->getcrosststamp) { 185 + err = -EOPNOTSUPP; 186 + break; 187 + } 188 + err = ptp->info->getcrosststamp(ptp->info, &xtstamp); 189 + if (err) 190 + break; 191 + 192 + ts = ktime_to_timespec64(xtstamp.device); 193 + precise_offset.device.sec = ts.tv_sec; 194 + precise_offset.device.nsec = ts.tv_nsec; 195 + ts = ktime_to_timespec64(xtstamp.sys_realtime); 196 + precise_offset.sys_realtime.sec = ts.tv_sec; 197 + precise_offset.sys_realtime.nsec = ts.tv_nsec; 198 + ts = ktime_to_timespec64(xtstamp.sys_monoraw); 199 + precise_offset.sys_monoraw.sec = ts.tv_sec; 200 + precise_offset.sys_monoraw.nsec = ts.tv_nsec; 201 + if (copy_to_user((void __user *)arg, &precise_offset, 202 + sizeof(precise_offset))) 203 + err = -EFAULT; 185 204 break; 186 205 187 206 case PTP_SYS_OFFSET:
+8
include/linux/ptp_clock_kernel.h
··· 38 38 }; 39 39 }; 40 40 41 + struct system_device_crosststamp; 41 42 /** 42 43 * struct ptp_clock_info - decribes a PTP hardware clock 43 44 * ··· 67 66 * 68 67 * @gettime64: Reads the current time from the hardware clock. 69 68 * parameter ts: Holds the result. 69 + * 70 + * @getcrosststamp: Reads the current time from the hardware clock and 71 + * system clock simultaneously. 72 + * parameter cts: Contains timestamp (device,system) pair, 73 + * where system time is realtime and monotonic. 70 74 * 71 75 * @settime64: Set the current time on the hardware clock. 72 76 * parameter ts: Time value to set. ··· 111 105 int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta); 112 106 int (*adjtime)(struct ptp_clock_info *ptp, s64 delta); 113 107 int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts); 108 + int (*getcrosststamp)(struct ptp_clock_info *ptp, 109 + struct system_device_crosststamp *cts); 114 110 int (*settime64)(struct ptp_clock_info *p, const struct timespec64 *ts); 115 111 int (*enable)(struct ptp_clock_info *ptp, 116 112 struct ptp_clock_request *request, int on);
+12 -1
include/uapi/linux/ptp_clock.h
··· 51 51 int n_per_out; /* Number of programmable periodic signals. */ 52 52 int pps; /* Whether the clock supports a PPS callback. */ 53 53 int n_pins; /* Number of input/output pins. */ 54 - int rsv[14]; /* Reserved for future use. */ 54 + /* Whether the clock supports precise system-device cross timestamps */ 55 + int cross_timestamping; 56 + int rsv[13]; /* Reserved for future use. */ 55 57 }; 56 58 57 59 struct ptp_extts_request { ··· 81 79 * one as a system time stamp. 82 80 */ 83 81 struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1]; 82 + }; 83 + 84 + struct ptp_sys_offset_precise { 85 + struct ptp_clock_time device; 86 + struct ptp_clock_time sys_realtime; 87 + struct ptp_clock_time sys_monoraw; 88 + unsigned int rsv[4]; /* Reserved for future use. */ 84 89 }; 85 90 86 91 enum ptp_pin_function { ··· 133 124 #define PTP_SYS_OFFSET _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset) 134 125 #define PTP_PIN_GETFUNC _IOWR(PTP_CLK_MAGIC, 6, struct ptp_pin_desc) 135 126 #define PTP_PIN_SETFUNC _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc) 127 + #define PTP_SYS_OFFSET_PRECISE \ 128 + _IOWR(PTP_CLK_MAGIC, 8, struct ptp_sys_offset_precise) 136 129 137 130 struct ptp_extts_event { 138 131 struct ptp_clock_time t; /* Time event occured. */