summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-15 13:51:27 +0530
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-15 13:51:27 +0530
commit2d6d57f889f3a5e7d19009c560ea2002cdde9fb8 (patch)
treeaa1e373320daae5eaf98d0a58a2ae65858087cd8 /drivers
parenta53fcff8fc7530f59a8171824ed586200df724a0 (diff)
parentbc484a5096732cd858771cccd3164ec985bdc03d (diff)
Merge tag 'timers-ptp-2026-06-13' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip
Pull timekeeping updates from Thomas Gleixner: "Updates for NTP/timekeeping and PTP: - Expand timekeeping snapshot mechanisms The various snapshot functions are mostly used for PTP to collect "atomic" snapshots of various involved clocks. They lack support for the recently introduced AUX clocks and do not provide the underlying counter value (e.g. TSC) to user space. Exposing the counter value snapshot allows for better control and steering. Convert the hard wired ktime_get_snapshot() to take a clock ID, which allows the caller to select the clock ID to be captured along with CLOCK_MONONOTONIC_RAW. Additionally capture the underlying hardware counter value and the clock source ID of the counter. Expand the hardware based snapshot capture where devices provide a mechanism to snapshot the hardware PTP clock and the system counter (usually via PCI/PTM) to support AUX clocks and also provide the captured counter value back to the caller and not only the clock timestamps derived from it. - Add a new optional read_snapshot() callback to clocksources That is required to capture atomic snapshots from clocksources which are derived from TSC with a scaling mechanism (e.g. Hyper-V, KVMclock). The value pair is handed back in the snapshot structure to the callers, so they can do the necessary correlations in a more precise way. This touches usage sites of the affected functions and data structure all over the tree, but stays fully backwards compatible for the existing user space exposed interfaces. New PTP IOCTLs will provide access to the extended functionality in later kernel versions" * tag 'timers-ptp-2026-06-13' of gitolite.kernel.org:pub/scm/linux/kernel/git/tip/tip: (28 commits) ptp: vmclock: Use hw_cycles from snapshot for precise TSC pairing x86/kvmclock: Implement read_snapshot() for kvmclock clocksource clocksource/hyperv: Implement read_snapshot() for TSC page clocksource timekeeping: Add clocksource read_snapshot() method and hw_cycles to snapshot ptp: Switch to ktime_get_snapshot_id() for pre/post timestamps timekeeping: Add support for AUX clock cross timestamping timekeeping: Remove system_device_crosststamp::sys_realtime ALSA: hda/common: Use system_device_crosststamp::sys_systime wifi: iwlwifi: Use system_device_crosststamp::sys_systime ptp: Use system_device_crosststamp::sys_systime timekeeping: Prepare for cross timestamps on arbitrary clock IDs timekeeping: Remove ktime_get_snapshot() virtio_rtc: Use provided clock ID for history snapshot net/mlx5: Use provided clock ID for history snapshot igc: Use provided clock ID for history snapshot ice/ptp: Use provided clock ID for history snapshot wifi: iwlwifi: Adopt PTP cross timestamps to core changes timekeeping: Add CLOCK ID to system_device_crosststamp timekeeping: Add system_counterval_t to struct system_device_crosststamp timekeeping: Add CLOCK_AUX support for ktime_get_snapshot_id() ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clocksource/hyperv_timer.c37
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c8
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c5
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h1
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mld/ptp.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ptp.c7
-rw-r--r--drivers/pps/generators/pps_gen-dummy.c6
-rw-r--r--drivers/pps/generators/pps_gen_tio.c6
-rw-r--r--drivers/ptp/ptp_chardev.c18
-rw-r--r--drivers/ptp/ptp_ocp.c11
-rw-r--r--drivers/ptp/ptp_vmclock.c29
-rw-r--r--drivers/virtio/virtio_rtc_ptp.c2
14 files changed, 78 insertions, 65 deletions
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
index e9f5034a1bc8..df567795d175 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -444,6 +444,22 @@ static u64 notrace read_hv_clock_tsc_cs(struct clocksource *arg)
return read_hv_clock_tsc();
}
+static u64 notrace read_hv_clock_tsc_cs_snapshot(struct clocksource *arg,
+ struct clocksource_hw_snapshot *chs)
+{
+ u64 time;
+
+ if (hv_read_tsc_page_tsc(tsc_page, &chs->hw_cycles, &time)) {
+ chs->hw_csid = CSID_X86_TSC;
+ } else {
+ chs->hw_cycles = 0;
+ chs->hw_csid = CSID_GENERIC;
+ time = read_hv_clock_msr();
+ }
+
+ return time;
+}
+
static u64 noinstr read_hv_sched_clock_tsc(void)
{
return (read_hv_clock_tsc() - hv_sched_clock_offset) *
@@ -492,18 +508,19 @@ static int hv_cs_enable(struct clocksource *cs)
#endif
static struct clocksource hyperv_cs_tsc = {
- .name = "hyperv_clocksource_tsc_page",
- .rating = 500,
- .read = read_hv_clock_tsc_cs,
- .mask = CLOCKSOURCE_MASK(64),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .suspend= suspend_hv_clock_tsc,
- .resume = resume_hv_clock_tsc,
+ .name = "hyperv_clocksource_tsc_page",
+ .rating = 500,
+ .read = read_hv_clock_tsc_cs,
+ .read_snapshot = read_hv_clock_tsc_cs_snapshot,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .suspend = suspend_hv_clock_tsc,
+ .resume = resume_hv_clock_tsc,
#ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK
- .enable = hv_cs_enable,
- .vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK,
+ .enable = hv_cs_enable,
+ .vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK,
#else
- .vdso_clock_mode = VDSO_CLOCKMODE_NONE,
+ .vdso_clock_mode = VDSO_CLOCKMODE_NONE,
#endif
};
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index c72c2bfdcffb..2697073dbf90 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -2310,10 +2310,10 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
goto out;
}
- t1 = timespec64_to_ns(&ptp_sts_before.pre_ts);
- t2 = timespec64_to_ns(&ptp_sts_before.post_ts);
- t3 = timespec64_to_ns(&ptp_sts_after.pre_ts);
- t4 = timespec64_to_ns(&ptp_sts_after.post_ts);
+ t1 = ktime_to_ns(ptp_sts_before.pre_sts.systime);
+ t2 = ktime_to_ns(ptp_sts_before.post_sts.systime);
+ t3 = ktime_to_ns(ptp_sts_after.pre_sts.systime);
+ t4 = ktime_to_ns(ptp_sts_after.post_sts.systime);
/* Mid point, corresponds to pre-reset PTPCLKVAL */
t12 = t1 + (t2 - t1) / 2;
/* Mid point, corresponds to post-reset PTPCLKVAL, aka 0 */
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 36df742c326c..f9e4ec6f7ebb 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -2065,11 +2065,13 @@ static const struct ice_crosststamp_cfg ice_crosststamp_cfg_e830 = {
/**
* struct ice_crosststamp_ctx - Device cross timestamp context
* @snapshot: snapshot of system clocks for historic interpolation
+ * @snapshot_clock_id: System clock ID for @snapshot
* @pf: pointer to the PF private structure
* @cfg: pointer to hardware configuration for cross timestamp
*/
struct ice_crosststamp_ctx {
struct system_time_snapshot snapshot;
+ clockid_t snapshot_clock_id;
struct ice_pf *pf;
const struct ice_crosststamp_cfg *cfg;
};
@@ -2115,7 +2117,7 @@ static int ice_capture_crosststamp(ktime_t *device,
}
/* Snapshot system time for historic interpolation */
- ktime_get_snapshot(&ctx->snapshot);
+ ktime_get_snapshot_id(ctx->snapshot_clock_id, &ctx->snapshot);
/* Program cmd to master timer */
ice_ptp_src_cmd(hw, ICE_PTP_READ_TIME);
@@ -2176,6 +2178,7 @@ static int ice_ptp_getcrosststamp(struct ptp_clock_info *info,
{
struct ice_pf *pf = ptp_info_to_pf(info);
struct ice_crosststamp_ctx ctx = {
+ .snapshot_clock_id = cts->clock_id,
.pf = pf,
};
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 17236813965d..46d625b15f44 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -326,6 +326,7 @@ struct igc_adapter {
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
ktime_t ptp_reset_start; /* Reset time in clock mono */
struct system_time_snapshot snapshot;
+ clockid_t snapshot_clock_id;
struct mutex ptm_lock; /* Only allow one PTM transaction at a time */
char fw_version[32];
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index 3d6b2264164a..b40aba9ab685 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -1049,7 +1049,7 @@ static int igc_phc_get_syncdevicetime(ktime_t *device,
*/
do {
/* Get a snapshot of system clocks to use as historic value. */
- ktime_get_snapshot(&adapter->snapshot);
+ ktime_get_snapshot_id(adapter->snapshot_clock_id, &adapter->snapshot);
igc_ptm_trigger(hw);
@@ -1103,6 +1103,8 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
/* This blocks until any in progress PTM transactions complete */
mutex_lock(&adapter->ptm_lock);
+ adapter->snapshot_clock_id = cts->clock_id;
+
ret = get_device_system_crosststamp(igc_phc_get_syncdevicetime,
adapter, &adapter->snapshot, cts);
mutex_unlock(&adapter->ptm_lock);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
index d785f1b4f2e1..5df786133e4b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
@@ -340,7 +340,7 @@ static int mlx5_ptp_getcrosststamp(struct ptp_clock_info *ptp,
goto unlock;
}
- ktime_get_snapshot(&history_begin);
+ ktime_get_snapshot_id(cts->clock_id, &history_begin);
err = get_device_system_crosststamp(mlx5_mtctr_syncdevicetime, mdev,
&history_begin, cts);
@@ -366,7 +366,7 @@ static int mlx5_ptp_getcrosscycles(struct ptp_clock_info *ptp,
goto unlock;
}
- ktime_get_snapshot(&history_begin);
+ ktime_get_snapshot_id(cts->clock_id, &history_begin);
err = get_device_system_crosststamp(mlx5_mtctr_syncdevicecyclestime,
mdev, &history_begin, cts);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c
index c65f4b56a327..f829156d42b3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c
@@ -250,7 +250,8 @@ iwl_mld_phc_get_crosstimestamp(struct ptp_clock_info *ptp,
/* System (wall) time */
ktime_t sys_time;
- memset(xtstamp, 0, sizeof(struct system_device_crosststamp));
+ if (xtstamp->clock_id != CLOCK_REALTIME)
+ return -ENOTSUPP;
ret = iwl_mld_get_crosstimestamp_fw(mld, &gp2, &sys_time);
if (ret) {
@@ -270,7 +271,7 @@ iwl_mld_phc_get_crosstimestamp(struct ptp_clock_info *ptp,
/* System monotonic raw time is not used */
xtstamp->device = ns_to_ktime(gp2_ns);
- xtstamp->sys_realtime = sys_time;
+ xtstamp->sys_systime = sys_time;
return ret;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
index f7b620136c85..bcd6f7cead2a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c
@@ -160,13 +160,14 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp,
/* System (wall) time */
ktime_t sys_time;
- memset(xtstamp, 0, sizeof(struct system_device_crosststamp));
-
if (!mvm->ptp_data.ptp_clock) {
IWL_ERR(mvm, "No PHC clock registered\n");
return -ENODEV;
}
+ if (xtstamp->clock_id != CLOCK_REALTIME)
+ return -ENOTSUPP;
+
mutex_lock(&mvm->mutex);
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SYNCED_TIME)) {
ret = iwl_mvm_get_crosstimestamp_fw(mvm, &gp2, &sys_time);
@@ -184,7 +185,7 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp,
/* System monotonic raw time is not used */
xtstamp->device = (ktime_t)gp2_ns;
- xtstamp->sys_realtime = sys_time;
+ xtstamp->sys_systime = sys_time;
out:
mutex_unlock(&mvm->mutex);
diff --git a/drivers/pps/generators/pps_gen-dummy.c b/drivers/pps/generators/pps_gen-dummy.c
index 547fa7fe29f4..a4395543c4bb 100644
--- a/drivers/pps/generators/pps_gen-dummy.c
+++ b/drivers/pps/generators/pps_gen-dummy.c
@@ -39,11 +39,7 @@ static void pps_gen_ktimer_event(struct timer_list *unused)
static int pps_gen_dummy_get_time(struct pps_gen_device *pps_gen,
struct timespec64 *time)
{
- struct system_time_snapshot snap;
-
- ktime_get_snapshot(&snap);
- *time = ktime_to_timespec64(snap.real);
-
+ ktime_get_real_ts64(time);
return 0;
}
diff --git a/drivers/pps/generators/pps_gen_tio.c b/drivers/pps/generators/pps_gen_tio.c
index de00a85bfafa..9483d126ada0 100644
--- a/drivers/pps/generators/pps_gen_tio.c
+++ b/drivers/pps/generators/pps_gen_tio.c
@@ -189,11 +189,7 @@ static int pps_tio_gen_enable(struct pps_gen_device *pps_gen, bool enable)
static int pps_tio_get_time(struct pps_gen_device *pps_gen,
struct timespec64 *time)
{
- struct system_time_snapshot snap;
-
- ktime_get_snapshot(&snap);
- *time = ktime_to_timespec64(snap.real);
-
+ ktime_get_real_ts64(time);
return 0;
}
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index c61cf9edac48..dc23cd708cfe 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -317,8 +317,8 @@ typedef int (*ptp_crosststamp_fn)(struct ptp_clock_info *,
static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg,
ptp_crosststamp_fn crosststamp_fn)
{
+ struct system_device_crosststamp xtstamp = { .clock_id = CLOCK_REALTIME };
struct ptp_sys_offset_precise precise_offset;
- struct system_device_crosststamp xtstamp;
struct timespec64 ts;
int err;
@@ -333,7 +333,7 @@ static long ptp_sys_offset_precise(struct ptp_clock *ptp, void __user *arg,
ts = ktime_to_timespec64(xtstamp.device);
precise_offset.device.sec = ts.tv_sec;
precise_offset.device.nsec = ts.tv_nsec;
- ts = ktime_to_timespec64(xtstamp.sys_realtime);
+ ts = ktime_to_timespec64(xtstamp.sys_systime);
precise_offset.sys_realtime.sec = ts.tv_sec;
precise_offset.sys_realtime.nsec = ts.tv_nsec;
ts = ktime_to_timespec64(xtstamp.sys_monoraw);
@@ -386,15 +386,19 @@ static long ptp_sys_offset_extended(struct ptp_clock *ptp, void __user *arg,
return err;
/* Filter out disabled or unavailable clocks */
- if (sts.pre_ts.tv_sec < 0 || sts.post_ts.tv_sec < 0)
+ if (!sts.pre_sts.valid || !sts.post_sts.valid)
return -EINVAL;
- extoff->ts[i][0].sec = sts.pre_ts.tv_sec;
- extoff->ts[i][0].nsec = sts.pre_ts.tv_nsec;
extoff->ts[i][1].sec = ts.tv_sec;
extoff->ts[i][1].nsec = ts.tv_nsec;
- extoff->ts[i][2].sec = sts.post_ts.tv_sec;
- extoff->ts[i][2].nsec = sts.post_ts.tv_nsec;
+
+ ts = ktime_to_timespec64(sts.pre_sts.systime);
+ extoff->ts[i][0].sec = ts.tv_sec;
+ extoff->ts[i][0].nsec = ts.tv_nsec;
+
+ ts = ktime_to_timespec64(sts.post_sts.systime);
+ extoff->ts[i][2].sec = ts.tv_sec;
+ extoff->ts[i][2].nsec = ts.tv_nsec;
}
return copy_to_user(arg, extoff, sizeof(*extoff)) ? -EFAULT : 0;
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 735385539b9f..8231c2d7785e 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -1491,11 +1491,8 @@ __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts,
}
ptp_read_system_postts(sts);
- if (sts && bp->ts_window_adjust) {
- s64 ns = timespec64_to_ns(&sts->post_ts);
-
- sts->post_ts = ns_to_timespec64(ns - bp->ts_window_adjust);
- }
+ if (sts && bp->ts_window_adjust)
+ sts->post_sts.systime -= bp->ts_window_adjust;
time_ns = ioread32(&bp->reg->time_ns);
time_sec = ioread32(&bp->reg->time_sec);
@@ -4600,8 +4597,8 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
struct timespec64 sys_ts;
s64 pre_ns, post_ns, ns;
- pre_ns = timespec64_to_ns(&sts.pre_ts);
- post_ns = timespec64_to_ns(&sts.post_ts);
+ pre_ns = ktime_to_ns(sts.pre_sts.systime);
+ post_ns = ktime_to_ns(sts.post_sts.systime);
ns = (pre_ns + post_ns) / 2;
ns += (s64)bp->utc_tai_offset * NSEC_PER_SEC;
sys_ts = ns_to_timespec64(ns);
diff --git a/drivers/ptp/ptp_vmclock.c b/drivers/ptp/ptp_vmclock.c
index 8b630eb916b5..eebdcd5ebc08 100644
--- a/drivers/ptp/ptp_vmclock.c
+++ b/drivers/ptp/ptp_vmclock.c
@@ -101,7 +101,6 @@ static int vmclock_get_crosststamp(struct vmclock_state *st,
struct timespec64 *tspec)
{
ktime_t deadline = ktime_add(ktime_get(), VMCLOCK_MAX_WAIT);
- struct system_time_snapshot systime_snapshot;
uint64_t cycle, delta, seq, frac_sec;
#ifdef CONFIG_X86
@@ -132,17 +131,19 @@ static int vmclock_get_crosststamp(struct vmclock_state *st,
* will be derived from the *same* counter value.
*
* If the system isn't using the same counter, then the value
- * from ktime_get_snapshot() will still be used as pre_ts, and
- * ptp_read_system_postts() is called to populate postts after
- * calling get_cycles().
- *
- * The conversion to timespec64 happens further down, outside
- * the seq_count loop.
+ * from ptp_read_system_prets() will still be used as pre_ts,
+ * and ptp_read_system_postts() is called to populate postts
+ * after calling get_cycles().
*/
if (sts) {
- ktime_get_snapshot(&systime_snapshot);
- if (systime_snapshot.cs_id == st->cs_id) {
- cycle = systime_snapshot.cycles;
+ ptp_read_system_prets(sts);
+ if (sts->pre_sts.cs_id == st->cs_id) {
+ cycle = sts->pre_sts.cycles;
+ sts->post_sts = sts->pre_sts;
+ } else if (sts->pre_sts.hw_csid == st->cs_id &&
+ sts->pre_sts.hw_cycles) {
+ cycle = sts->pre_sts.hw_cycles;
+ sts->post_sts = sts->pre_sts;
} else {
cycle = get_cycles();
ptp_read_system_postts(sts);
@@ -180,12 +181,6 @@ static int vmclock_get_crosststamp(struct vmclock_state *st,
system_counter->cs_id = st->cs_id;
}
- if (sts) {
- sts->pre_ts = ktime_to_timespec64(systime_snapshot.real);
- if (systime_snapshot.cs_id == st->cs_id)
- sts->post_ts = sts->pre_ts;
- }
-
return 0;
}
@@ -272,7 +267,7 @@ static int ptp_vmclock_getcrosststamp(struct ptp_clock_info *ptp,
if (ret == -ENODEV) {
struct system_time_snapshot systime_snapshot;
- ktime_get_snapshot(&systime_snapshot);
+ ktime_get_snapshot_id(CLOCK_REALTIME, &systime_snapshot);
if (systime_snapshot.cs_id == CSID_X86_TSC ||
systime_snapshot.cs_id == CSID_X86_KVM_CLK) {
diff --git a/drivers/virtio/virtio_rtc_ptp.c b/drivers/virtio/virtio_rtc_ptp.c
index f84599950cd4..ff8d834493dc 100644
--- a/drivers/virtio/virtio_rtc_ptp.c
+++ b/drivers/virtio/virtio_rtc_ptp.c
@@ -139,7 +139,7 @@ static int viortc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
if (ret)
return ret;
- ktime_get_snapshot(&history_begin);
+ ktime_get_snapshot_id(xtstamp->clock_id, &history_begin);
if (history_begin.cs_id != cs_id)
return -EOPNOTSUPP;