From patchwork Fri Mar 4 01:57:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 591720 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 36C491422BE for ; Fri, 4 Mar 2016 12:59:25 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b=SDcVZNRD; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758277AbcCDB7G (ORCPT ); Thu, 3 Mar 2016 20:59:06 -0500 Received: from mail-pa0-f49.google.com ([209.85.220.49]:36263 "EHLO mail-pa0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756725AbcCDB5P (ORCPT ); Thu, 3 Mar 2016 20:57:15 -0500 Received: by mail-pa0-f49.google.com with SMTP id fi3so23347838pac.3 for ; Thu, 03 Mar 2016 17:57:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=SYfkCouFmIUoXKrVuiEA3lrhVJ4OKgqLv67kQgoV784=; b=SDcVZNRD83OBX8Yhlc7X/OQUuB8h4c/XoM1uWQuxphu7PzlHaLzMlpEbWBPWhPWU0Q jqMJIJ6HG7JnetZyfi+2XNU/3+Go0nFRFbfAQySlTWEFYwjkH38/EthBQ+VTrt/MjeYa 5yc9UmmeZa/6yp+1QRXIz0p/duXV9OHujB5Zo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=SYfkCouFmIUoXKrVuiEA3lrhVJ4OKgqLv67kQgoV784=; b=ZNKI5UfLhiM/1OBaRRgYs8ZX10NY3/y4mX0OrQ/pj1Tb44nU6T/ka7kaVhIeSFQUz+ JB3fZKO15WtvNXrZl2A5gMyvvljqtyJP0iQepO3J9iE9ioVSCpyi/sx0Y9OvEi/7rg5O WviWasmso+h0fYvvjcjxPkuMYUS96J15eOfTXJAekrV+d0xl18D67Ywg/IGD7N0jOMWO oDESs6mVHJHRxh3IZze4padAGZeVvCER2sjbnBj7XGvioigcvT6FbLWslIXd5B6240XZ A96ZZtbqWbfWXCvkzuTV3DuEem4gUnOetAg3IVWPPBZZ2lDE3s5RDYCOHRblN5elOJyR MPig== X-Gm-Message-State: AD7BkJKEj5a6FP0lkiY/PR4suV027kO7vdKbPTlfCUEghin+CHj5BAFQ4qb5ePEEhhccArPI X-Received: by 10.66.102.104 with SMTP id fn8mr8362451pab.129.1457056634600; Thu, 03 Mar 2016 17:57:14 -0800 (PST) Received: from localhost.localdomain (c-76-115-103-22.hsd1.or.comcast.net. [76.115.103.22]) by smtp.gmail.com with ESMTPSA id w12sm983409pfa.79.2016.03.03.17.57.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 03 Mar 2016 17:57:14 -0800 (PST) From: John Stultz To: lkml Cc: "Christopher S. Hall" , Prarit Bhargava , Richard Cochran , Thomas Gleixner , Ingo Molnar , Andy Lutomirski , kevin.b.stanton@intel.com, kevin.j.clarke@intel.com, hpa@zytor.com, jeffrey.t.kirsher@intel.com, netdev@vger.kernel.org, John Stultz Subject: [PATCH 4/8] time: Add driver cross timestamp interface for higher precision time synchronization Date: Thu, 3 Mar 2016 17:57:02 -0800 Message-Id: <1457056626-4899-5-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1457056626-4899-1-git-send-email-john.stultz@linaro.org> References: <1457056626-4899-1-git-send-email-john.stultz@linaro.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: "Christopher S. Hall" ACKNOWLEDGMENT: cross timestamp code was developed by Thomas Gleixner . It has changed considerably and any mistakes are mine. The precision with which events on multiple networked systems can be synchronized using, as an example, PTP (IEEE 1588, 802.1AS) is limited by the precision of the cross timestamps between the system clock and the device (timestamp) clock. Precision here is the degree of simultaneity when capturing the cross timestamp. Currently the PTP cross timestamp is captured in software using the PTP device driver ioctl PTP_SYS_OFFSET. Reads of the device clock are interleaved with reads of the realtime clock. At best, the precision of this cross timestamp is on the order of several microseconds due to software latencies. Sub-microsecond precision is required for industrial control and some media applications. To achieve this level of precision hardware supported cross timestamping is needed. The function get_device_system_crosstimestamp() allows device drivers to return a cross timestamp with system time properly scaled to nanoseconds. The realtime value is needed to discipline that clock using PTP and the monotonic raw value is used for applications that don't require a "real" time, but need an unadjusted clock time. The get_device_system_crosstimestamp() code calls back into the driver to ensure that the system counter is within the current timekeeping update interval. Modern Intel hardware provides an Always Running Timer (ART) which is exactly related to TSC through a known frequency ratio. The ART is routed to devices on the system and is used to precisely and simultaneously capture the device clock with the ART. Cc: Prarit Bhargava Cc: Richard Cochran Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Andy Lutomirski 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 Reviewed-by: Thomas Gleixner Signed-off-by: Christopher S. Hall [jstultz: Reworked to remove extra structures and simplify calling] Signed-off-by: John Stultz --- include/linux/timekeeping.h | 35 ++++++++++++++++++++++++++++ kernel/time/timekeeping.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 7817591..4a2ca65 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -280,6 +280,41 @@ struct system_time_snapshot { }; /* + * struct system_device_crosststamp - system/device cross-timestamp + * (syncronized capture) + * @device: Device time + * @sys_realtime: Realtime simultaneous with device time + * @sys_monoraw: Monotonic raw simultaneous with device time + */ +struct system_device_crosststamp { + ktime_t device; + ktime_t sys_realtime; + ktime_t sys_monoraw; +}; + +/* + * struct system_counterval_t - system counter value with the pointer to the + * corresponding clocksource + * @cycles: System counter value + * @cs: Clocksource corresponding to system counter value. Used by + * timekeeping code to verify comparibility of two cycle values + */ +struct system_counterval_t { + cycle_t cycles; + struct clocksource *cs; +}; + +/* + * Get cross timestamp between system clock and device clock + */ +extern int get_device_system_crosststamp( + int (*get_time_fn)(ktime_t *device_time, + struct system_counterval_t *system_counterval, + void *ctx), + void *ctx, + struct system_device_crosststamp *xtstamp); + +/* * Simultaneously snapshot realtime and monotonic raw clocks */ extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index af19a49..dba595c 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -908,6 +908,62 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot) EXPORT_SYMBOL_GPL(ktime_get_snapshot); /** + * get_device_system_crosststamp - Synchronously capture system/device timestamp + * @sync_devicetime: Callback to get simultaneous device time and + * system counter from the device driver + * @xtstamp: Receives simultaneously captured system and device time + * + * Reads a timestamp from a device and correlates it to system time + */ +int get_device_system_crosststamp(int (*get_time_fn) + (ktime_t *device_time, + struct system_counterval_t *sys_counterval, + void *ctx), + void *ctx, + struct system_device_crosststamp *xtstamp) +{ + struct system_counterval_t system_counterval; + struct timekeeper *tk = &tk_core.timekeeper; + ktime_t base_real, base_raw; + s64 nsec_real, nsec_raw; + unsigned long seq; + int ret; + + do { + seq = read_seqcount_begin(&tk_core.seq); + /* + * Try to synchronously capture device time and a system + * counter value calling back into the device driver + */ + ret = get_time_fn(&xtstamp->device, &system_counterval, ctx); + if (ret) + return ret; + + /* + * Verify that the clocksource associated with the captured + * system counter value is the same as the currently installed + * timekeeper clocksource + */ + if (tk->tkr_mono.clock != system_counterval.cs) + return -ENODEV; + + base_real = ktime_add(tk->tkr_mono.base, + tk_core.timekeeper.offs_real); + base_raw = tk->tkr_raw.base; + + nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, + system_counterval.cycles); + nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, + system_counterval.cycles); + } while (read_seqcount_retry(&tk_core.seq, seq)); + + xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real); + xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw); + return 0; +} +EXPORT_SYMBOL_GPL(get_device_system_crosststamp); + +/** * do_gettimeofday - Returns the time of day in a timeval * @tv: pointer to the timeval to be set *