arch/arm/stm32, sched, net: hardware PTP timestamping, ADJFREQ/ADJPHASE, and tickless fixes - #20148
daniel-p-carvalho wants to merge 13 commits into
Conversation
df6136c to
70cf835
Compare
|
|
||
| /* PTP Timestamping *********************************************************/ | ||
|
|
||
| #define SIOCG_TX_HW_TIMESTAMP _SIOC(0x0046) /* Get hardware TX timestamp */ |
There was a problem hiding this comment.
does Linux define the similar ioctl?
There was a problem hiding this comment.
No, Linux doesn't have a direct equivalent for any of the three - it exposes each NIC's PTP hardware clock as its own /dev/ptpN character device with a clockid_t, disciplined via the standard POSIX clock_adjtime() syscall rather than a dedicated network ioctl. TX timestamp retrieval similarly goes through SO_TIMESTAMPING + the socket error queue (MSG_ERRQUEUE/SCM_TIMESTAMPING), which NuttX's socket layer doesn't implement (MSG_ERRQUEUE is defined for API compat but unused, and there's a comment in inet_sockif.c noting SO_TIMESTAMPING as future work).
While looking into this I found drivers/timers/ptp_clock.c already implements a generic upper-half PTP hardware clock framework matching Linux's /dev/ptpN model closely - PTP_CLOCK_ADJTIME handling ADJ_FREQUENCY/ADJ_OFFSET via struct timex, the dynamic-clockid-to-fd conversion, etc. It has no registered lower-half driver anywhere in the tree yet, and its adjfine/adjphase ops map almost directly onto what this PR already implements in stm32_eth_ptp_adjust()/stm32_eth_ptp_adjphase(). I didn't know about it when I wrote this PR; migrating to it as a lower-half driver looks like the right direction for SIOCS_PTP_ADJFREQ/SIOCS_PTP_ADJPHASE, dropping both in favor of /dev/ptp0. SIOCG_TX_HW_TIMESTAMP is unrelated to that framework though - it's per-packet TX timestamp retrieval, not clock discipline, and there's no equivalent facility in ptp_clock.c for it; the real Linux equivalent there is SO_TIMESTAMPING/MSG_ERRQUEUE, which as noted isn't implemented in NuttX, so I don't see a smaller-scope alternative to keeping that one as a plain ioctl for now.
Would you rather I do the /dev/ptp0 migration for ADJFREQ/ADJPHASE in this PR, or land the current ioctls now and follow up separately?
There was a problem hiding this comment.
While looking into this I found drivers/timers/ptp_clock.c already implements a generic upper-half PTP hardware clock framework matching Linux's /dev/ptpN model closely - PTP_CLOCK_ADJTIME handling ADJ_FREQUENCY/ADJ_OFFSET via struct timex, the dynamic-clockid-to-fd conversion, etc. It has no registered lower-half driver anywhere in the tree yet, and its adjfine/adjphase ops map almost directly onto what this PR already implements in stm32_eth_ptp_adjust()/stm32_eth_ptp_adjphase(). I didn't know about it when I wrote this PR;
ptp driver framework is implemented by @Donny9 to let eth driver provide ptp clock in a portable way.
migrating to it as a lower-half driver looks like the right direction for SIOCS_PTP_ADJFREQ/SIOCS_PTP_ADJPHASE, dropping both in favor of /dev/ptp0.
yes, I think so.
SIOCG_TX_HW_TIMESTAMP is unrelated to that framework though - it's per-packet TX timestamp retrieval, not clock discipline, and there's no equivalent facility in ptp_clock.c for it; the real Linux equivalent there is SO_TIMESTAMPING/MSG_ERRQUEUE, which as noted isn't implemented in NuttX, so I don't see a smaller-scope alternative to keeping that one as a plain ioctl for now.
@wenquan2015 do some improvement in this area, which may simplify your code.
Would you rather I do the /dev/ptp0 migration for ADJFREQ/ADJPHASE in this PR, or land the current ioctls now and follow up separately?
it's better to algin your improvement inside both kernel and userspace to Linux design, so we can use other ptp library and utility in the future.
There was a problem hiding this comment.
@daniel-p-carvalho Hi, I've already implemented the SO_TIMESTAMPING + MSG_ERRQUEUE TX timestamp delivery and will submitt PRs to NuttX mainline this week after resolving the conflict. The full Linux-style flow is in place: sender tags iob->io_conn, driver captures the timestamp and loops the IOB back via RX path, userspace retrieves it with recvmsg(MSG_ERRQUEUE) + SCM_TIMESTAMPING cmsg.
@xiaoxiang781216 #20161
There was a problem hiding this comment.
Sounds good, I'll migrate SIOCS_PTP_ADJFREQ/SIOCS_PTP_ADJPHASE to /dev/ptp0 (registering a lower-half driver against drivers/timers/ptp_clock.c) in this PR.
For TX timestamp delivery, I'd rather hold off on migrating SIOCG_TX_HW_TIMESTAMP to SO_TIMESTAMPING until apache/nuttx#20161 merges. Should I keep this PR open as-is for that follow-up once apache/nuttx#20161 merges, mark it as draft in the meantime, or close it and submit a fresh PR later instead? Happy to do whichever fits your workflow better.
@wenquan2015 nice work, looking forward to building on top of it once it's in.
There was a problem hiding this comment.
it's better to split your pr into there new pr:
- the general network improvement or bugfix
- implement stm32 eth ptp driver
- implement stm32 eth hardware timestamp
it's fine to reuse this pr for item 2 or 3 if you want.
| /* PTP Timestamping *********************************************************/ | ||
|
|
||
| #define SIOCG_TX_HW_TIMESTAMP _SIOC(0x0046) /* Get hardware TX timestamp */ | ||
| #define SIOCS_PTP_ADJFREQ _SIOC(0x0047) /* Set PTP hardware frequency adjustment (ppb) */ |
|
|
||
| #define SIOCG_TX_HW_TIMESTAMP _SIOC(0x0046) /* Get hardware TX timestamp */ | ||
| #define SIOCS_PTP_ADJFREQ _SIOC(0x0047) /* Set PTP hardware frequency adjustment (ppb) */ | ||
| #define SIOCS_PTP_ADJPHASE _SIOC(0x0048) /* Set PTP hardware phase adjustment (ns) */ |
3f45f30 to
84e534c
Compare
Every other timer driver block in this Make.defs sets TMRDEPPATH and TMRVPATH so DEPPATH/VPATH include this directory. CONFIG_PTP_CLOCK and CONFIG_PTP_CLOCK_DUMMY were the only two missing it, leaving ptp_clock.c/ptp_clock_dummy.c unreachable via VPATH and without a generated dependency file when no other timer driver in this file is also selected. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 6d38122)
stm32_receive() called pkt_input() before stm32_eth_ptp_convert_rxtime(), so every packet handed to a packet socket carried the previous frame's RX timestamp instead of its own in dev->d_rxtime. Reorder so the timestamp is converted first. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 9bfa20d)
pkt_in() suppresses delivery of a received packet whose iob pointer matches the connection's last transmitted iob (pendiob), to avoid delivering a frame the driver echoes back to its own receiver. The iob pool is small and recycled quickly, so a genuinely different incoming packet can reuse the same iob slot our last transmission used, and gets silently dropped as a false positive. Track the transmitted length alongside the iob pointer and require both to match before treating a received packet as a self-echo. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 4dbf181)
Set ETH_MACCR_ROD unconditionally when configuring the MAC. In half-duplex mode the MAC otherwise reflects every frame it transmits back to its own receiver, flooding the receive path with our own traffic right as a genuine reply arrives. The bit has no effect in full-duplex (confirmed on our hardware: fduplex=1), so setting it unconditionally is safe and changes nothing observable for boards already running full-duplex. The sibling stm32f7 driver has the same gap (ETH_MACCR_ROD cleared but never set) and stm32h7's equivalent ETH_MACCR_DO bit has the same issue; both are left out of scope here since only m3m4_v1 hardware was available to validate against. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 41536cb)
Upstream already fixed the adjtime() clamp sign and consumption bug under CONFIG_CLOCK_TIMEKEEPING (5db3aa9, e37509e). What remained missing for CONFIG_SCHED_TICKLESS: clock_update_wall_time() was never called on a schedule, so a pending adjtime() correction only applied whenever something else happened to call clock_timekeeping_get_wall_time() or clock_update_wall_time() directly, with no periodic progress otherwise. - nxsched_process_timer() (sched_processtickless.c) now calls clock_update_wall_time() every tick under CONFIG_CLOCK_TIMEKEEPING, mirroring what the non-tickless sched_processtick.c path already does - clock_timekeeping_get_wall_time() calls clock_update_wall_time() itself, so a reader gets the current value instead of depending on the tick handler having already run - Honor CONFIG_CLOCK_ADJTIME_SLEWLIMIT_PPM as the slew limit instead of a fixed 500 usec/s - uint64_t -> clock_t type cleanups to match the counter's actual width Assisted-by: Gemini:gemini-3.8-flash-medium Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
The STM32 timer only generates a compare-match interrupt on an exact CNT == CCR equality. up_timer_start() could arm a compare value the free-running counter had already passed by the time the register write took effect, missing that equality entirely and leaving the interrupt pending forever until the 32-bit counter wraps (~71 minutes at 1MHz) - observed to hang any blocking wait in the system (network TX, ifup) that depends on a tickless-driven wakeup. Add stm32_tickless_trigint(), which forces the compare event via the timer's EGR software-trigger bit, and call it whenever up_timer_start() detects (after arming) that the counter has already reached or passed the target. Also handle a zero or negative requested delay by triggering immediately instead of arming a stale compare value, and unify up_timer_cancel()'s rollover-safe "already elapsed" comparison between the 16-bit and 32-bit tickless variants. Assisted-by: Gemini:gemini-3.8-flash-medium Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit ad2732b)
Define SIOCG_TX_HW_TIMESTAMP to allow user-space applications (such as PTP daemons) to synchronously retrieve the hardware transmit timestamp captured by Ethernet MAC controllers. Add handling in net_ioctl_ifreq_arglen() and dispatch to dev->d_ioctl() via netdev_ifr_ioctl(), passing the user timespec pointer stored in ifr_data. Assisted-by: Gemini:gemini-3.8-flash-medium Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit df528c7)
Implement hardware TX timestamping in the STM32 Ethernet MAC driver under CONFIG_STM32_ETH_TIMESTAMP_TX (Milestone M3): - Unify hardware timestamp to CLOCK_REALTIME conversion across RX and TX via stm32_eth_ptp_convert_hwtime(). - Inspect outgoing frames in stm32_transmit() to recognize PTP event frames (Layer 2 EtherType 0x88F7 and IPv4 UDP port 319 with event message types <= 3). - Enable hardware timestamp capture on the transmit descriptor via ETH_TDES0_TTSE and track the descriptor in a parallel tx_meta table indexed by pointer arithmetic against g_txtable. - In stm32_freeframe(), verify ETH_TDES0_TTSS upon transmission completion, extract raw timestamps from tdes7 (seconds) and tdes6 (subseconds), convert to CLOCK_REALTIME, and post the waiting semaphore. - Implement SIOCG_TX_HW_TIMESTAMP in stm32_ioctl() with a 50 ms timeout to deliver t3/t1 to user space synchronously. Assisted-by: Gemini:gemini-3.8-flash-medium Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 81d4241)
Define SIOCS_PTP_ADJFREQ to allow user-space applications (such as PTP daemons) to apply a continuous frequency (rate) correction, in parts per billion, to a PTP-capable Ethernet MAC's hardware counter. Add handling in net_ioctl_ifreq_arglen() and dispatch to dev->d_ioctl() via netdev_ifr_ioctl(), mirroring SIOCG_TX_HW_TIMESTAMP. Assisted-by: Gemini:gemini-3.8-flash-medium Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 287e21f)
…FREQ. Implement SIOCS_PTP_ADJFREQ in stm32_ioctl(), calling the existing stm32_eth_ptp_adjust() to write the PTP addend register (ETH_PTPTSAR). Fix a sign bug in stm32_eth_ptp_adjust() found while validating this path on hardware: addend was uint64_t, so "addend * ppb" promoted a negative ppb to a huge unsigned value before the division, corrupting the result for any negative (clock running fast) adjustment - exactly the sign our board's crystal needs. Change addend to int64_t and cast ppb explicitly so the multiply and divide stay in signed arithmetic. This disciplines the MAC's own internal PTP counter - used for RX/TX hardware timestamp precision and the PPS output on PB5 (CONFIG_STM32_ETH_PTP_GPIO) - not CLOCK_REALTIME, which under CLOCK_TIMEKEEPING is sourced from TIM2 and unaffected by this register. Register writes were confirmed correct via live diagnostic log (TTSE/TTSS/tdes6/tdes7 all valid); PPS phase accuracy against the GNSS Grandmaster still needs oscilloscope validation before this is considered fully proven. Assisted-by: Gemini:gemini-3.8-flash-medium Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 144bb4e)
Define SIOCS_PTP_ADJPHASE to let user-space applications nudge a PTP-capable Ethernet MAC's hardware counter phase by a signed nanosecond delta, without resetting any frequency correction already in effect. Add handling in net_ioctl_ifreq_arglen() and dispatch to dev->d_ioctl() via netdev_ifr_ioctl(), mirroring SIOCS_PTP_ADJFREQ. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 0b8a770)
…JPHASE. Implement SIOCS_PTP_ADJPHASE in stm32_ioctl(), calling a new stm32_eth_ptp_adjphase() that writes a signed nanosecond delta to ETH_PTPTSHUR/ETH_PTPTSLUR and triggers the System Time Update (ETH_PTPTSCR_TSSTU) bit - unlike stm32_eth_ptp_init()'s TSSTI path, this does not reset the addend register, so any rate correction already applied via SIOCS_PTP_ADJFREQ is preserved. This closes the gap left by stm32_eth_ptp_init(0): the MAC's PTP counter starts phase-arbitrary every time the interface comes up, and nothing previously ever realigned it to the master's time - only its rate got corrected. This affects the PPS output pin (PB5, CONFIG_STM32_ETH_PTP_GPIO) directly. Register math verified by hand (round-trip through ptp_to_timespec()'s conversion for both positive and negative deltas); build and checkpatch clean. Oscilloscope validation of PPS phase alignment against the GNSS Grandmaster still pending. Assisted-by: Claude:claude-sonnet-5 Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com> (cherry picked from commit 3cc6e89)
The MAC hardware counter is the PTP clock reference. Delivering its raw timestamp directly (instead of synthesizing one against CLOCK_REALTIME, which starts at an arbitrary boot-time phase) lets the PTP daemon close the feedback loop and phase-lock the MAC counter - and therefore the physical PPS output - to the master. This folds in and supersedes two earlier attempts at the same fix that are dropped from this series (g_rtc_lock scope, elapsed-time subtraction), both made moot by this rewrite. Assisted-by: Gemini:gemini-3.8-flash-medium Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
84e534c to
67293c8
Compare
Implement lower-half PTP hardware clock operations (struct ptp_lowerhalf_s and struct ptp_ops_s) in the STM32 Ethernet driver and register it with the generic PTP clock framework (drivers/timers/ptp_clock.c) to expose /dev/ptp0. Supported operations: - adjfine: adjust PTP clock frequency in parts per billion (ppb) - adjphase: adjust PTP clock phase via hardware TSSTU - adjtime: shift PTP clock time by signed delta in nanoseconds - gettime: atomic double-read of hardware timestamp registers - settime: initialize hardware timestamp counter via TSSTI - getres: return 1 ns clock resolution Also fix a sign bug in frequency trim where uint64_t addend promoted negative ppb adjustments to unsigned, corrupting frequency trim for crystals running faster than nominal. Follow-up to apache#20148 per review recommendation to use the standard POSIX /dev/ptp0 character driver instead of custom socket ioctls. Assisted-by: Gemini:gemini-3.8-pro Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Implement lower-half PTP hardware clock operations (struct ptp_lowerhalf_s and struct ptp_ops_s) in the STM32 Ethernet driver and register it with the generic PTP clock framework (drivers/timers/ptp_clock.c) to expose /dev/ptp0. Supported operations: - adjfine: adjust PTP clock frequency in parts per billion (ppb) - adjphase: adjust PTP clock phase via hardware TSSTU - adjtime: shift PTP clock time by signed delta in nanoseconds - gettime: atomic double-read of hardware timestamp registers - settime: initialize hardware timestamp counter via TSSTI - getres: return 1 ns clock resolution Also fix a sign bug in stm32_eth_ptp_adjust() where uint64_t addend promoted negative ppb adjustments to unsigned, corrupting frequency trim for crystals running faster than nominal. Follow-up to apache#20148 per review recommendation to use the standard POSIX /dev/ptp0 character driver instead of custom socket ioctls. Assisted-by: Gemini:gemini-3.8-pro Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Implement lower-half PTP hardware clock operations (struct ptp_lowerhalf_s and struct ptp_ops_s) in the STM32 Ethernet driver and register it with the generic PTP clock framework (drivers/timers/ptp_clock.c) to expose /dev/ptp0. Supported operations: - adjfine: adjust PTP clock frequency in parts per billion (ppb) - adjphase: adjust PTP clock phase via hardware TSSTU - adjtime: shift PTP clock time by signed delta in nanoseconds - gettime: atomic double-read of hardware timestamp registers - settime: initialize hardware timestamp counter via TSSTI - getres: return 1 ns clock resolution Also fix a sign bug in stm32_eth_ptp_adjust() where uint64_t addend promoted negative ppb adjustments to unsigned, corrupting frequency trim for crystals running faster than nominal. Follow-up to apache#20148 per review recommendation to use the standard POSIX /dev/ptp0 character driver instead of custom socket ioctls. Assisted-by: Gemini:gemini-3.8-pro Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Summary
Why change is necessary (fix, update, new feature)?
Getting
apps/netutils/ptpdhardware-syntonized to a real,GPS-disciplined PTP Grandmaster (Toradex Colibri iMX7 running
linuxptp'sptp4l, IEC/IEEE 61850-9-3 P2P profile) against anSTM32F4Discovery required several pieces of kernel/driver support that
didn't exist yet: hardware TX timestamping (RX timestamping already
existed but had an ordering bug), a way for the PTP daemon to trim the
MAC's own hardware clock frequency and phase (not just the software
CLOCK_REALTIME), and a couple of unrelated bugs that only surfacedonce the board was driven hard enough by this workload (a tickless
timer race, a network self-transmit loopback false positive, and a
gap in
CONFIG_SCHED_TICKLESS+CONFIG_CLOCK_TIMEKEEPINGwall-timeslewing). This PR is the kernel/driver side; the PTP daemon side
(peer-delay support, ioctl consumption) is a companion, not-yet-opened
apache/nuttx-appsPR building on the already-open #3779.What functional part of the code is being changed?
arch/arm/src/common/stm32/stm32_eth_m3m4_v1.c(+Kconfig.eth):hardware TX timestamping, direct hardware-counter RX/TX timestamp
delivery,
SIOCS_PTP_ADJFREQ/SIOCS_PTP_ADJPHASEsupport,self-transmit reception disable, RX timestamp/
pkt_input()orderingnet/netdev/netdev_ioctl.c+include/nuttx/net/ioctl.h: three newsocket ioctls (
SIOCG_TX_HW_TIMESTAMP,SIOCS_PTP_ADJFREQ,SIOCS_PTP_ADJPHASE)net/pkt/*: self-transmit loopback filter false-positive fixarch/arm/src/common/stm32/stm32_tickless_m3m4_v1.c: TIM2compare-match race fix
sched/clock/clock_timekeeping.c,sched/sched/sched_processtickless.c:drive wall-clock adjtime slewing from the tickless tick handler
drivers/timers/Make.defs: build path for PTP clock driversHow does the change exactly work (what will change and how)? Twelve
commits, each independently described in its own message:
drivers/timers: Add TMRDEPPATH/TMRVPATH for PTP clock drivers.arch/arm/stm32: Convert RX hardware timestamp before pkt_input().— fixes every packet-socket RX timestamp being off by one frame
net/pkt: Require matching length for self-transmit loopback filter.arch/arm/stm32: Disable reception of self-transmitted frames.— sets
ETH_MACCR_ROD, no-op in full-duplexsched: Drive wall-clock adjtime slewing from the tickless tick handler.— builds on top of already-merged upstream fixes for the
adjtime()clamp sign/consumption bug (5db3aa9, e37509e);this adds the missing periodic driver for
CONFIG_SCHED_TICKLESSarch/arm/stm32: Fix TIM2 compare-match race in tickless timer driver.— could hang any blocking wait depending on a tickless wakeup
net/netdev: Add SIOCG_TX_HW_TIMESTAMP socket ioctl command.arch/arm/stm32: Support hardware transmit timestamping.net/netdev: Add SIOCS_PTP_ADJFREQ socket ioctl command.arch/arm/stm32: Support PTP hardware frequency trim via SIOCS_PTP_ADJFREQ.net/netdev: Add SIOCS_PTP_ADJPHASE socket ioctl command.arch/arm/stm32: Support PTP hardware phase alignment via SIOCS_PTP_ADJPHASE.fix(stm32_eth): deliver direct hardware counter timestamps for PTP.— RX/TX timestamps for
CONFIG_STM32_ETH_TIMESTAMP_RX/_TXnowreflect the MAC's own hardware counter directly instead of being
synthesized against
CLOCK_REALTIME(which starts at an arbitraryboot-time phase when
CONFIG_STM32_ETH_PTP_RTC_HIRESis not set),letting a PTP daemon actually phase-lock the hardware counter (and
therefore the physical PPS output pin) to a master
Impact
SIOCG_TX_HW_TIMESTAMP,SIOCS_PTP_ADJFREQ,SIOCS_PTP_ADJPHASE) are additive; no behavior change for existingcallers.
stm32_eth_m3m4_v1.cRX/TX timestamp semantics change only forboards with
CONFIG_STM32_ETH_TIMESTAMP_RX/_TXenabled withoutCONFIG_STM32_ETH_PTP_RTC_HIRES(this basic PTP core is shared byseveral STM32 F1/F2/F4-family Ethernet MACs).
ETH_MACCR_RODis now set unconditionally; verified no-op infull-duplex (the only mode available on the hardware used to test
this), behavior changes only for half-duplex users of this driver.
net/pktloopback filter change only tightens an existingfalse-positive-prone check (additive length comparison).
CONFIG_SCHED_TICKLESS+CONFIG_CLOCK_TIMEKEEPINGcombination:wall-clock adjtime slewing now actually progresses; no effect
outside that specific Kconfig combination.
stm32_tickless_m3m4_v1.c): fixes a racethat could hang indefinitely; affects all users of that tickless
timer driver family.
Testing
HIL bench: STM32F4Discovery (custom out-of-tree board
stm32f4discovery-ext, STM32F407VGT6, DP83848C RMII PHY on anEthernet baseboard) running as PTP slave via
apps/netutils/ptpd,against a real GPS-disciplined PTP Grandmaster (Toradex Colibri iMX7 +
X-NUCLEO-GNSS1A1 GNSS module,
linuxptp'sptp4l, IEC/IEEE61850-9-3 P2P delay-mechanism profile) as master.
Verified with a digital oscilloscope comparing the GPS Grandmaster's
1PPS output against the STM32's own hardware-generated
ETH_PPS_OUTsignal (
PB5): before this series, the STM32's PPS edge landed at anarbitrary, permanently-frozen phase offset from the master's edge;
after, it phase-locks onto the master's edge following the daemon's
initial clock jump and stays aligned. Also queried
pmc -u -b 0 "GET PORT_STATS_NP"on the Grandmaster to confirmtx_Pdelay_Resp/rx_Pdelay_Req(and, for the E2E path validated by#3779,
Delay_Req/Delay_Resp) counters incrementing as expected.Host: Ubuntu 24.04,
arm-none-eabi-gcctoolchain, built and flashedstm32f4discovery-ext:ethraw(custom out-of-tree board config, notpart of this PR) via NuttX's standard
make/make flashflow.Known limitations
frame.
stm32_eth_m3m4_v1.c'sCONFIG_STM32_ETH_TIMESTAMP_TXtracks the MAC-captured timestamp through a single
tx_ptp_sem/tx_last_ts/tx_last_validtriple per interface, notper frame. If two PTP event frames were transmitted back-to-back
before the first one's timestamp was collected via
SIOCG_TX_HW_TIMESTAMP, the second transmit'snxsem_reset()wouldoverwrite the first's in-flight state, and a reader could get the
wrong frame's timestamp. Not an issue with the current consumer:
apps/netutils/ptpd/ptpd.c'sptp_sendmsg()is synchronous - itsends and immediately ioctls for the timestamp before returning, and
ptpd only ever has one event message in flight at a time. Would
become a real bug for any future consumer that sends PTP event
frames concurrently/asynchronously (e.g. a multi-port Transparent
Clock or Boundary Clock). Fix, if ever needed: key the pending
timestamp by something like the frame's PTP sequenceId instead of
keeping a single "most recent" slot.