Skip to content

Conversation

@agagniere
Copy link
Collaborator

@agagniere agagniere commented Aug 16, 2025

Context

The value stored in the read-write attribute ts_window_adjust is a number of nanoseconds subtracted to the post_ts timestamp of the PHC readings of the ioctl PTP_SYS_OFFSET_EXTENDED, to compensate for PCI delays.
Its initial value is set by estimating PCI delay.

Bug

The PCI delay estimation starts with the value U64_MAX and makes 3 measurements, taking the minimum value.
However because the delay was stored in a s64, U64_MAX was interpreted as -1, which compared as smaller than any positive values measured.
Then, that delay is divided by 10 and placed in ts_window_adjust, which is a u32.
So ts_window_adjust ends up with (u32)((U64_MAX >> 5) * 3) inside, which is $4294967293$

Symptom

The consequence was that the post_ts of PTP_SYS_OFFSET_EXTENDED was substracted $4.29$ seconds

As a consequence chrony rejected all readings from the PHC

Difficulty to diagnose

Using cat to read the attribute value showed -3 because the format flags %d was used instead of %u, resulting in a re-interpret cast.

Fixes

  1. Using U32_MAX as initial value for PCI delays: no one is expecting an ioread to take more than $4$ s
  2. Fixing format flags across the whole driver

@agagniere agagniere self-assigned this Aug 16, 2025
@agagniere agagniere added the bug Something isn't working label Aug 16, 2025
ts_window_adjust and utc_tai_offset are u32
timespec64's members are s64 and long
ktime_t is s64

s64  -> %lli
long -> %li
u32  -> %u
u16  -> %hu
u8   -> %hhu
1UL  -> %lu
For some reason the driver may be unable to estimate PCI timing.
In that situation (which happens 100% of the time on the various hardware I tried)
the ts_window_adjust would be assinged to (u32)((U64_MAX >> 5) * 3) = 4294967293

because of this PTP_SYS_OFFSET_EXTENDED's post_ts is substracted 4.3s, making it smaller than pre_ts.
The delay was initialized to U64_MAX, while it was a s64, so its initial value was interpreted as -1
Then when it was compared to positive delays, the lowest value was always -1
Then when it was divided by 10 and cast into an u32, that u32 ended up with a value of U32_MAX - 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants