Re: [PATCH v6 net-next 1/7] ptp: Add ioctls for PHC timestamps with quality attributes
Maciek Machnikowski <[email protected]> Tue, 4 Aug 2026 19:59:14 +0200
| Newsgroups | gmane.linux.documentation,gmane.linux.network |
|---|---|
| Message-ID | <[email protected]> |
On 30/07/2026 01:37, Arthur Kiyanovski wrote:
> Introduce two new ioctls that extend existing PTP timestamp interfaces
> with clock quality information:
>
>
> +/*
> + * Clock status values for struct ptp_clock_attrs.status
> + */
> +enum ptp_clock_status {
> + /* Clock synchronization status cannot be reliably determined */
> + PTP_CLOCK_STATUS_UNKNOWN = 0,
> +
> + /* Clock is acquiring synchronization */
> + PTP_CLOCK_STATUS_INITIALIZING = 1,
> +
> + /* Clock is synchronized and maintained accurately by the device */
> + PTP_CLOCK_STATUS_SYNCED = 2,
> +
> + /*
> + * Clock is drifting but remains within acceptable error bounds;
> + * error_bound is valid and can be trusted.
> + */
> + PTP_CLOCK_STATUS_HOLDOVER = 3,
> +
> + /*
> + * Clock is free-running: not currently disciplined toward a reference
> + * (unlike HOLDOVER), but coasting on a known oscillator. error_bound
> + * remains valid and can be trusted, and typically grows over time.
> + */
> + PTP_CLOCK_STATUS_FREE_RUNNING = 4,
> +
> + /*
> + * Clock is considered broken (e.g. the oscillator is faulty or
> + * abnormally unstable): error_bound cannot be trusted. A clock that is
> + * merely unsynchronized or resynchronizing should report
> + * PTP_CLOCK_STATUS_UNKNOWN or PTP_CLOCK_STATUS_INITIALIZING instead.
> + */
> + PTP_CLOCK_STATUS_UNRELIABLE = 5
What is the practical use of UNRELIABLE vs UNKNOWN.
I think it can be simplified to UNRELIABLE, SYNCED and HOLDOVER. All
clocks will start in UNRELIABLE, switch to SYNCED whenever the clock
gets synchronized correctly and enter HOLDOVER if it was at the SYNCED
state and report the last synced for that state. Status INITIALIZING has
no practical meaning and requires more work from the APIs, and
HOLDOVER->FREE_RUNNING state transition is undefined (what is
"acceptable" for one application won't be acceptable for another)
> +};
> +
> +/*
> + * Clock timescale values for struct ptp_clock_attrs.timescale.
> + *
> + * These definitions describe the mathematical properties and reference
> + * epochs of the timescale provided by the PHC.
> + *
> + * Discipline: Describes the frequency/phase steering behavior.
> + * Continuity: Describes whether the timeline is uninterrupted.
> + */
> +enum ptp_clock_timescale {
> + /* Unknown or unspecified timescale */
> + PTP_TIMESCALE_UNKNOWN = 0,
> +
> + /********************* Absolute Atomic Timescales *********************
> + * These timescales are continuous, monotonic standards based on atomic
> + * physics. They do not experience phase jumps.
> + **********************************************************************/
> +
> + /**
> + * International Atomic Time (TAI)
> + * Epoch: 1958-01-01 00:00:00.
> + * Continuity: Strictly monotonic and continuous; no leap seconds.
> + * Discipline: Primary atomic reference; no phase jumps.
> + */
> + PTP_TIMESCALE_TAI = 1,
> +
> + /**
> + * Terrestrial Time (TT)
> + * Epoch: 1958-01-01 00:00:00.
> + * Continuity: Strictly monotonic and continuous; no leap seconds.
> + * Discipline: Defined as TAI + 32.184s constant offset.
> + */
> + PTP_TIMESCALE_TT = 2,
> +
> + /**
> + * Global Positioning System (GPS) Time
> + * Epoch: 1980-01-06 00:00:00.
> + * Continuity: Strictly monotonic and continuous; no leap seconds.
> + * Discipline: Defined by the GPS constellation; fixed offset from TAI.
> + */
> + PTP_TIMESCALE_GPS = 3,
> +
> + /****************** UTC-Based Timescales (Civil Time) *****************
> + * These timescales are derived from TAI but adjusted to align with
> + * the Earth's rotation, primarily through leap seconds.
> + **********************************************************************/
> +
> + /**
> + * Coordinated Universal Time (UTC) - Wall-clock (CLOCK_REALTIME)
> + * Epoch: 1970-01-01 00:00:00 (Unix epoch).
> + * Continuity: Discontinuous; subject to 1-second leap second
> + * phase jumps.
> + * Discipline: Frequency steered; incorporates leap second corrections.
> + *
> + * Note: Leap-smeared UTC MUST NOT be advertised as PTP_TIMESCALE_UTC.
> + * Smear algorithms are not standardized and the resulting timescale
> + * is ambiguous. Implementations using smeared UTC MUST advertise
> + * PTP_TIMESCALE_UNKNOWN or PTP_TIMESCALE_PROPRIETARY instead.
> + */
> + PTP_TIMESCALE_UTC = 4,
> +
> + /**
> + * POSIX Time (Unix Time)
> + * Epoch: 1970-01-01 00:00:00.
> + * Continuity: Discontinuous; leap seconds handled by
> + * repeating/skipping values.
> + * Discipline: Follows UTC frequency steering and phase jumps.
> + */
> + PTP_TIMESCALE_POSIX = 5,
> +
> + /****************** System-Relative Monotonic Clocks ******************
> + * These timescales are relative to a system event (like boot)
> + * and are not synchronized to an external atomic standard.
> + **********************************************************************/
> +
> + /**
> + * Monotonic System Clock (CLOCK_MONOTONIC)
> + * Epoch: Arbitrary (System boot time).
> + * Continuity: Strictly monotonic; no leap seconds.
> + * Discipline: Frequency steered to match system reference;
> + * does not advance during suspend.
> + */
> + PTP_TIMESCALE_MONOTONIC = 6,
> +
> + /**
> + * Raw Monotonic System Clock (CLOCK_MONOTONIC_RAW)
> + * Epoch: Arbitrary (System boot time).
> + * Continuity: Strictly monotonic; no leap seconds.
> + * Discipline: Raw hardware oscillator; no frequency steering
> + * or discipline.
> + */
> + PTP_TIMESCALE_MONOTONIC_RAW = 7,
> +
> + /**
> + * Boot Time System Clock (CLOCK_BOOTTIME)
> + * Epoch: Arbitrary (System boot time).
> + * Continuity: Strictly monotonic and continuous; no leap seconds.
> + * Discipline: Frequency steered to match system reference;
> + * advances during suspend.
> + */
> + PTP_TIMESCALE_BOOTTIME = 8,
> +
> + /********************** Vendor-Specific Timescale *********************/
> +
> + /* A proprietary or vendor-specific timescale with custom rules. */
> + PTP_TIMESCALE_PROPRIETARY = 9,
> +};
Do we need this many timescales defined here? Can't we just use the
notion of TIMESCALE_ARBITRARY and TIMESCALE_ABSOLUTE with the UTC
offset? CLOCK_MONOTONIC / MONOTONIC_RAW are really ARBITRARY, is there
any value of differentating between those two?
> +
> /*
> * struct ptp_clock_time - represents a time value
> *
> @@ -94,6 +237,136 @@ struct ptp_clock_time {
> __u32 reserved;
> };
>
> +/*
> + * Hardware counter identifiers for struct ptp_sys_time.sys_counter_id
> + */
> +enum ptp_counter_id {
> + /* Counter value not available or type not specified */
> + PTP_COUNTER_UNKNOWN = 0,
> +
> + /* x86 Time Stamp Counter (TSC) */
> + PTP_COUNTER_X86_TSC = 1,
> +
> + /* ARM Generic Timer virtual counter */
> + PTP_COUNTER_ARM_ARCH = 2,
> +};
> +
> +/* Valid flags for struct ptp_clock_attrs.valid */
> +#define PTP_ATTRS_VALID_ERROR_BOUND (1 << 0)
> +#define PTP_ATTRS_VALID_TIMESCALE (1 << 1)
> +#define PTP_ATTRS_VALID_STATUS (1 << 2)
> +
> +/**
> + * struct ptp_clock_attrs - quality attributes for a PHC timestamp
> + *
> + * @valid: Bitmask of PTP_ATTRS_VALID_* indicating which fields
> + * are populated. Zero means no attributes available.
> + * @error_bound: Maximum error (an upper bound, in nanoseconds) between the
> + * returned device_time and true time on the advertised
> + * @timescale; a worst-case bound, not a statistical estimate.
> + * Valid only when PTP_ATTRS_VALID_ERROR_BOUND is set, and must
> + * not be trusted when @status is PTP_CLOCK_STATUS_UNKNOWN or
> + * PTP_CLOCK_STATUS_UNRELIABLE.
> + * @timescale: Clock timescale (enum ptp_clock_timescale). Valid only
> + * when PTP_ATTRS_VALID_TIMESCALE is set.
> + * @status: Synchronization status (enum ptp_clock_status). Valid
> + * only when PTP_ATTRS_VALID_STATUS is set. Transitions between
> + * states are device-specific; there are no kernel-defined
> + * thresholds relating @status to @error_bound.
> + * @rsv: Reserved for future use, must be zero.
> + */
> +struct ptp_clock_attrs {
> + __u32 valid;
> + __u32 error_bound;
> + __u32 timescale;
> + __u32 status;
> + __u32 rsv[4];
> +};
This does not look like a practical model. Error bounds changes over
time and will get stale by the time you transfer them over IOCTL.
I think a more practical approach would be to return error_bound
alongside the anchor_timestamp at which it was measured. For example you
can define master_offset for the RX timestamp of the Sync packet, or the
offset for the last 1PPS signal you received. This should be
complemented by some drift_factor that would define how fast it grows.
If you capture the time from the PHC you can use the formula of
error_bound+(phc_time - anchor_timestamp)*drift_factor to interpolate
the boundaries.
Do we want to squash all errors into a single error_bound - it may make
sense to add the hw_error and sync_error - hw_error would squash
hw-based error bounds (such as clock resolution, GNSS precision) and
sync_error (which would hold the dynamic part derived from the sync
protocol)
Thanks,
Maciek