get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/567109/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 567109,
    "url": "http://patchwork.ozlabs.org/api/patches/567109/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/1452687149-11281-7-git-send-email-christopher.s.hall@intel.com/",
    "project": {
        "id": 46,
        "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api",
        "name": "Intel Wired Ethernet development",
        "link_name": "intel-wired-lan",
        "list_id": "intel-wired-lan.osuosl.org",
        "list_email": "intel-wired-lan@osuosl.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1452687149-11281-7-git-send-email-christopher.s.hall@intel.com>",
    "list_archive_url": null,
    "date": "2016-01-13T12:12:26",
    "name": "[v6,6/9] Add history to cross timestamp interface supporting slower devices",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "d958a68051c1c52c8707d74adc5ce7e0a1d6749c",
    "submitter": {
        "id": 66720,
        "url": "http://patchwork.ozlabs.org/api/people/66720/?format=api",
        "name": "Hall, Christopher S",
        "email": "christopher.s.hall@intel.com"
    },
    "delegate": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/users/68/?format=api",
        "username": "jtkirshe",
        "first_name": "Jeff",
        "last_name": "Kirsher",
        "email": "jeffrey.t.kirsher@intel.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/1452687149-11281-7-git-send-email-christopher.s.hall@intel.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/567109/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/567109/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<intel-wired-lan-bounces@lists.osuosl.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "intel-wired-lan@lists.osuosl.org"
        ],
        "Received": [
            "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ozlabs.org (Postfix) with ESMTP id BE7F2140297\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 14 Jan 2016 06:18:45 +1100 (AEDT)",
            "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 15CC494629;\n\tWed, 13 Jan 2016 19:18:45 +0000 (UTC)",
            "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id ahwwWJaEz0Fr; Wed, 13 Jan 2016 19:18:43 +0000 (UTC)",
            "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 0CF64947D4;\n\tWed, 13 Jan 2016 19:18:43 +0000 (UTC)",
            "from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\tby ash.osuosl.org (Postfix) with ESMTP id 603CA1C0F8E\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Jan 2016 19:18:40 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 904748C841\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Jan 2016 19:18:39 +0000 (UTC)",
            "from whitealder.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id CKmZUXxl+k-J for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Jan 2016 19:18:38 +0000 (UTC)",
            "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 8264E8C949\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Jan 2016 19:18:38 +0000 (UTC)",
            "from fmsmga003.fm.intel.com ([10.253.24.29])\n\tby fmsmga102.fm.intel.com with ESMTP; 13 Jan 2016 11:18:39 -0800",
            "from foofoo.jf.intel.com (HELO localhost.localdomain)\n\t([134.134.172.151])\n\tby FMSMGA003.fm.intel.com with ESMTP; 13 Jan 2016 11:18:38 -0800"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.22,290,1449561600\"; d=\"scan'208\";a=\"632939108\"",
        "From": "\"Christopher S. Hall\" <christopher.s.hall@intel.com>",
        "To": "tglx@linutronix.de, richardcochran@gmail.com, mingo@redhat.com,\n\tjohn.stultz@linaro.org, hpa@zytor.com, jeffrey.t.kirsher@intel.com",
        "Date": "Wed, 13 Jan 2016 04:12:26 -0800",
        "Message-Id": "<1452687149-11281-7-git-send-email-christopher.s.hall@intel.com>",
        "X-Mailer": "git-send-email 2.1.4",
        "In-Reply-To": "<1452687149-11281-1-git-send-email-christopher.s.hall@intel.com>",
        "References": "<1452687149-11281-1-git-send-email-christopher.s.hall@intel.com>",
        "Cc": "\"Christopher S. Hall\" <christopher.s.hall@intel.com>,\n\tkevin.b.stanton@intel.com, netdev@vger.kernel.org, x86@kernel.org,\n\tlinux-kernel@vger.kernel.org, intel-wired-lan@lists.osuosl.org",
        "Subject": "[Intel-wired-lan] [PATCH v6 6/9] Add history to cross timestamp\n\tinterface supporting slower devices",
        "X-BeenThere": "intel-wired-lan@lists.osuosl.org",
        "X-Mailman-Version": "2.1.18-1",
        "Precedence": "list",
        "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.lists.osuosl.org>",
        "List-Unsubscribe": "<http://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>",
        "List-Post": "<mailto:intel-wired-lan@lists.osuosl.org>",
        "List-Help": "<mailto:intel-wired-lan-request@lists.osuosl.org?subject=help>",
        "List-Subscribe": "<http://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@lists.osuosl.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "intel-wired-lan-bounces@lists.osuosl.org",
        "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@lists.osuosl.org>"
    },
    "content": "Another representative use case of time sync and the correlated\nclocksource (in addition to PTP noted above) is PTP synchronized\naudio.\n\nIn a streaming application, as an example, samples will be sent and/or\nreceived by multiple devices with a presentation time that is in terms\nof the PTP master clock. Synchronizing the audio output on these\ndevices requires correlating the audio clock with the PTP master\nclock. The more precise this correlation is, the better the audio\nquality (i.e. out of sync audio sounds bad).\n\nFrom an application standpoint, to correlate the PTP master clock with\nthe audio device clock, the system clock is used as a intermediate\ntimebase. The transforms such an application would perform are:\n\n    System Clock <-> Audio clock\n    System Clock <-> Network Device Clock [<-> PTP Master Clock]\n\nSuch audio applications make use of some existing ALSA library calls\nthat provide audio/system cross-timestamps (e.g.\nsnd_pcm_status_get_htstamp()). Previous driver implementations capture\nthese cross timestamps by reading the system clock (raw/mono/real) and\nthe device clock with greatest degree of simultaneity possible in\nsoftware.\n\nModern Intel platforms can perform a more accurate cross timestamp in\nhardware (ART,audio device clock).  The audio driver requires\nART->system time transforms -- the same as required for the network\ndriver. These platforms offload audio processing (including\ncross-timestamps) to a DSP which to ensure uninterrupted audio\nprocessing, communicates and response to the host only once every\nmillsecond. As a result is takes up to a millisecond for the DSP to\nreceive a request, the request is processed by the DSP, the audio\noutput hardware is polled for completion, the result is copied into\nshared memory, and the host is notified. All of these operation occur\non a millisecond cadence.  This transaction requires about 2 ms, but\nunder heavier workloads it may take up to 4 ms.\n\nIf update_wall_time() is called while waiting for a response within\nget_device_system_crosststamp() (from previous patch), a retry is\nattempted. This will occur if the cycle_interval (determined by\nCONFIG_HZ and mult/shift values) cycles elapse.\n\nAdding a history allows these slow devices the option of providing an\nART value outside of the retry loop. In this case, the callback\nprovided is an accessor function for the previously obtained counter\nvalue. If get_system_device_crosststamp() receives a counter value\nprevious to cycle_last, it consults the history provided as an\nargument in history_ref and interpolates the realtime and monotonic\nraw system time using the provided counter value. If there are any\nclock discontinuities, e.g. from calling settimeofday(), the monotonic\nraw time is interpolated in the usual way, but the realtime clock time\nis adjusted by scaling the monotonic raw adjustment.\n\nWhen an accessor function is used a history argument *must* be\nprovided. The history is initialized using ktime_get_snapshot() and\nmust be called before the counter values are read.\n\nWhen the history is used to interpolate timestamp values, the realtime\nclock time may be inaccurate to some degree. In general, the\nlonger the length of history the larger the interpolation error. If\nthere are discontinuities (large step changes) to the time, the error\ncan be very large.\n\nSigned-off-by: Christopher S. Hall <christopher.s.hall@intel.com>\n---\n include/linux/clocksource.h         |   4 ++\n include/linux/timekeeper_internal.h |   2 +\n include/linux/timekeeping.h         |   3 +-\n kernel/time/timekeeping.c           | 130 ++++++++++++++++++++++++++++++++++++\n 4 files changed, 138 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h\nindex cccbd1c..229aee0 100644\n--- a/include/linux/clocksource.h\n+++ b/include/linux/clocksource.h\n@@ -287,11 +287,15 @@ struct correlated_cs {\n  * @cycles:\tClocksource counter value to produce the system times\n  * @real:\tRealtime system time\n  * @raw:\tMonotonic raw system time\n+ * @clock_was_set_seq:\tThe sequence number of clock was set events\n+ * @cs_was_changed_seq:\tThe sequence number of clocksource change events\n  */\n struct system_time_snapshot {\n \tcycles_t\tcycles;\n \tktime_t\t\treal;\n \tktime_t\t\traw;\n+\tunsigned int\tclock_was_set_seq;\n+\tu8\t\tcs_was_changed_seq;\n };\n \n #endif /* _LINUX_CLOCKSOURCE_H */\ndiff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h\nindex 2524722..e880054 100644\n--- a/include/linux/timekeeper_internal.h\n+++ b/include/linux/timekeeper_internal.h\n@@ -50,6 +50,7 @@ struct tk_read_base {\n  * @offs_tai:\t\tOffset clock monotonic -> clock tai\n  * @tai_offset:\t\tThe current UTC to TAI offset in seconds\n  * @clock_was_set_seq:\tThe sequence number of clock was set events\n+ * @cs_was_changed_seq:\tThe sequence number of clocksource change events\n  * @next_leap_ktime:\tCLOCK_MONOTONIC time value of a pending leap-second\n  * @raw_time:\t\tMonotonic raw base time in timespec64 format\n  * @cycle_interval:\tNumber of clock cycles in one NTP interval\n@@ -91,6 +92,7 @@ struct timekeeper {\n \tktime_t\t\t\toffs_tai;\n \ts32\t\t\ttai_offset;\n \tunsigned int\t\tclock_was_set_seq;\n+\tu8\t\t\tcs_was_changed_seq;\n \tktime_t\t\t\tnext_leap_ktime;\n \tstruct timespec64\traw_time;\n \ndiff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h\nindex f5fe657..dff97c4 100644\n--- a/include/linux/timekeeping.h\n+++ b/include/linux/timekeeping.h\n@@ -295,13 +295,14 @@ struct sync_device_time_cb {\n \tvoid\t *ctx;\n };\n \n+struct system_time_snapshot;\n /*\n  * Get cross timestamp between system clock and device clock\n  */\n extern int get_device_system_crosststamp(struct sync_device_time_cb *cb,\n+\t\t\t\t\t struct system_time_snapshot *history,\n \t\t\t\t\t struct system_device_crosststamp *ts);\n \n-struct system_time_snapshot;\n /*\n  * Simultaneously snapshot realtime and monotonic raw clocks\n  */\ndiff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c\nindex 26049df..54554ac 100644\n--- a/kernel/time/timekeeping.c\n+++ b/kernel/time/timekeeping.c\n@@ -233,6 +233,7 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)\n \tu64 tmp, ntpinterval;\n \tstruct clocksource *old_clock;\n \n+\t++tk->cs_was_changed_seq;\n \told_clock = tk->tkr_mono.clock;\n \ttk->tkr_mono.clock = clock;\n \ttk->tkr_mono.read = clock->read;\n@@ -880,6 +881,8 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)\n \t\tseq = read_seqcount_begin(&tk_core.seq);\n \n \t\tnow = tk->tkr_mono.read(tk->tkr_mono.clock);\n+\t\tsystime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;\n+\t\tsystime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;\n \t\tbase_real = ktime_add(tk->tkr_mono.base,\n \t\t\t\t      tk_core.timekeeper.offs_real);\n \t\tbase_raw = tk->tkr_raw.base;\n@@ -932,14 +935,83 @@ EXPORT_SYMBOL(ktime_get_raw_and_real_ts64);\n #endif /* CONFIG_NTP_PPS */\n \n /**\n+ * adjust_historical_crosststamp - adjust crosstimestamp previous to current interval\n+ * @total_history_cycles:\tTotal history length in cycles\n+ * @partial_history_cycles:\tCycle offset into history (fractional part)\n+ * @total_history_monoraw:\tTotal history length in monotonic raw ns\n+ * @total_history_realtime:\tTotal history length in realtime ns\n+ * @discontinuity:\t\tTrue indicates clock was set on history period\n+ * @ts:\t\t\t\tCross timestamp that should be adjusted using\n+ *\tpartial/total ratio\n+ *\n+ * Helper function used by get_device_system_crosststamp() to correct the\n+ * crosstimestamp corresponding to the start of the current interval to the\n+ * system counter value (timestamp point) provided by the driver. The\n+ * total_history_* quantities are the total history starting at the provided\n+ * reference point and ending at the start of the current interval. The cycle\n+ * count between the driver timestamp point and the start of the current\n+ * interval is partial_history_cycles.\n+ */\n+static void adjust_historical_crosststamp(cycle_t total_history_cycles,\n+\t\t\t\t\t  cycle_t partial_history_cycles,\n+\t\t\t\t\t  ktime_t total_history_monoraw,\n+\t\t\t\t\t  ktime_t total_history_realtime,\n+\t\t\t\t\t  bool discontinuity,\n+\t\t\t\t\t  struct system_device_crosststamp *ts)\n+{\n+\tstruct timekeeper *tk = &tk_core.timekeeper;\n+\tu64 corr_monoraw;\n+\tu64 corr_realtime;\n+\n+\t/*\n+\t * Scale the monotonic raw time delta by:\n+\t *\tpartial_history_cycles / total_history_cycles\n+\t */\n+\tcorr_monoraw = (ktime_to_ns(total_history_monoraw) *\n+\t\t\tpartial_history_cycles) / total_history_cycles;\n+\t/*\n+\t * If there is a discontinuity in the history, scale monotonic raw\n+\t *\tcorrection by:\n+\t *\tmult(real)/mult(raw) yielding the realtime correction\n+\t * Otherwise, calculate the realtime correction similar to monotonic\n+\t *\traw calculation\n+\t */\n+\tif (discontinuity)\n+\t\tcorr_realtime = (corr_monoraw * tk->tkr_mono.mult) /\n+\t\t\ttk->tkr_raw.mult;\n+\telse\n+\t\tcorr_realtime = (ktime_to_ns(total_history_realtime) *\n+\t\t\t\t partial_history_cycles)/total_history_cycles;\n+\n+\t/* Fixup monotonic raw and real time time values */\n+\tts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_monoraw);\n+\tts->sys_realtime = ktime_sub_ns(ts->sys_realtime, corr_realtime);\n+}\n+\n+/*\n+ * cycle_between - true if test occurs chronologically between before and after\n+ */\n+static bool cycle_between(cycles_t before, cycles_t test, cycles_t after)\n+{\n+\tif (test > before && test < after)\n+\t\treturn true;\n+\tif (test < before && before > after)\n+\t\treturn true;\n+\treturn false;\n+}\n+\n+/**\n  * get_device_system_crosststamp - Synchronously capture system/device timestamp\n  * @sync_devicetime:\tCallback to get simultaneous device time and\n  *\tsystem counter from the device driver\n+ *@history_ref:\t\tHistorical reference point used to interpolate system\n+ *\ttime when counter provided by the driver is before the current interval\n  * @xtstamp:\t\tReceives simultaneously captured system and device time\n  *\n  * Reads a timestamp from a device and correlates it to system time\n  */\n int get_device_system_crosststamp(struct sync_device_time_cb *sync_devicetime,\n+\t\t\t\t  struct system_time_snapshot *history_ref,\n \t\t\t\t  struct system_device_crosststamp *xtstamp)\n {\n \tstruct timekeeper *tk = &tk_core.timekeeper;\n@@ -949,6 +1021,12 @@ int get_device_system_crosststamp(struct sync_device_time_cb *sync_devicetime,\n \tktime_t base_real;\n \ts64 nsec_raw;\n \ts64 nsec_real;\n+\tcycles_t cycles;\n+\tcycle_t now;\n+\tcycle_t interval_start;\n+\tunsigned int clock_was_set_seq;\n+\tu8 cs_was_changed_seq;\n+\tbool do_interp;\n \tint ret;\n \n \tdo {\n@@ -970,6 +1048,23 @@ int get_device_system_crosststamp(struct sync_device_time_cb *sync_devicetime,\n \t\t */\n \t\tif (tk->tkr_mono.clock != system_counterval.cs)\n \t\t\treturn -ENODEV;\n+\t\tcycles = system_counterval.cycles;\n+\n+\t\t/*\n+\t\t * Check whether the system counter value provided by the\n+\t\t * device driver is on the current timekeeping interval.\n+\t\t */\n+\t\tnow = tk->tkr_mono.read(tk->tkr_mono.clock);\n+\t\tinterval_start = tk->tkr_mono.cycle_last;\n+\t\tif (!cycle_between(interval_start, cycles, now)) {\n+\t\t\tcs_was_changed_seq = tk->cs_was_changed_seq;\n+\t\t\tclock_was_set_seq = tk->clock_was_set_seq;\n+\t\t\tcycles = interval_start;\n+\t\t\tdo_interp = true;\n+\t\t} else {\n+\t\t\tdo_interp = false;\n+\t\t}\n+\n \n \t\tbase_real = ktime_add(tk->tkr_mono.base,\n \t\t\t\t      tk_core.timekeeper.offs_real);\n@@ -983,6 +1078,41 @@ int get_device_system_crosststamp(struct sync_device_time_cb *sync_devicetime,\n \n \txtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real);\n \txtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw);\n+\n+\t/*\n+\t * Interpolate if necessary, adjusting back from the start of the\n+\t * current interval\n+\t */\n+\tif (do_interp) {\n+\t\tcycle_t total_history_cycles, partial_history_cycles;\n+\t\tktime_t history_monoraw, history_realtime;\n+\t\tbool discontinuity;\n+\n+\t\t/*\n+\t\t * Check that the counter value occurs after the provided\n+\t\t * history reference and that the history doesn't cross a\n+\t\t * clocksource change\n+\t\t */\n+\t\tif (!history_ref ||\n+\t\t    !cycle_between(history_ref->cycles,\n+\t\t\t\t   system_counterval.cycles, interval_start) ||\n+\t\t    history_ref->cs_was_changed_seq != cs_was_changed_seq)\n+\t\t\treturn -EINVAL;\n+\t\tpartial_history_cycles = cycles - system_counterval.cycles;\n+\t\thistory_monoraw = ktime_sub(xtstamp->sys_monoraw,\n+\t\t\t\t\t    history_ref->raw);\n+\t\thistory_realtime = ktime_sub(xtstamp->sys_realtime,\n+\t\t\t\t\t     history_ref->real);\n+\t\ttotal_history_cycles = cycles - history_ref->cycles;\n+\t\tdiscontinuity =\n+\t\t\thistory_ref->clock_was_set_seq != clock_was_set_seq;\n+\t\tadjust_historical_crosststamp(total_history_cycles,\n+\t\t\t\t\t      partial_history_cycles,\n+\t\t\t\t\t      history_monoraw,\n+\t\t\t\t\t      history_realtime, discontinuity,\n+\t\t\t\t\t      xtstamp);\n+\t}\n+\n \treturn 0;\n }\n EXPORT_SYMBOL_GPL(get_device_system_crosststamp);\n",
    "prefixes": [
        "v6",
        "6/9"
    ]
}