Skip to content

arch/arm/stm32h7: timestamp the transmitted frames in hardware - #20213

Draft
daniel-p-carvalho wants to merge 6 commits into
apache:masterfrom
daniel-p-carvalho:feat/stm32h7-ptp-tx-hw
Draft

daniel-p-carvalho wants to merge 6 commits into
apache:masterfrom
daniel-p-carvalho:feat/stm32h7-ptp-tx-hw

Conversation

@daniel-p-carvalho

Copy link
Copy Markdown
Contributor

Depends on #20148 and on #20212. Please do not merge this PR before them.

The first five commits below are those of #20211, #20212 and the first commit of #20148, and are reviewed there. Until they are merged they show up in this diff; only the last commit is new here. This PR stays a draft until then, and I will rebase it onto master so that it is reduced to that commit.

Summary

The STM32H7 MAC can capture a timestamp for every transmitted frame, but the driver only timestamped received frames (#20212). A PTP daemon using the peer-to-peer delay mechanism needs the transmit time of its Pdelay_Req from the hardware.

This PR adds STM32_ETH_TIMESTAMP_TX for the STM32H7, the option that #20148 defines for the legacy STM32 driver, delivered through the generic SO_TIMESTAMPING mechanism of the network stack (#20161): when a frame is flagged for timestamping, the driver keeps a copy of it, sets the timestamp enable bit in its descriptor and, when the transmission is done, reads the timestamp from the descriptor and loops the copy back to the AF_PACKET socket, where recvmsg(..., MSG_ERRQUEUE) returns it. The MAC writes the timestamp over the address of the buffer in the descriptor, so the driver keeps the buffer of these descriptors.

Impact

Testing

Built with STM32_ETH_TIMESTAMP_TX with and without STM32_ETH_TIMESTAMP_RX, without errors or warnings. ./tools/checkpatch.sh -g upstream/master..HEAD passes.

On hardware, with a custom STM32H753 board and a DP83848 PHY, against a GNSS-referenced ptp4l grandmaster using the IEC/IEEE 61850-9-3 profile, over AF_PACKET, with ptpd -2 -s -H -p /dev/ptp0 -B -P -i eth0 from apache/nuttx-apps#3782 and the transmit timestamps of apache/nuttx-apps#3791:

  • The peer delay was 9.0 to 9.4 us in every measurement, the same as the STM32F4 driver of arch/arm/stm32: hardware TX timestamping via SO_TIMESTAMPING #20148 against the same grandmaster (9.27 us).
  • The clock followed the grandmaster: phase differences of tens to hundreds of nanoseconds and a drift of 18 ppm, corrected through /dev/ptp0.
  • The PPS outputs of the STM32H7 and of the STM32F4 board, measured on an oscilloscope against the same grandmaster, differed by about 20 us, consistently.

The end-to-end mechanism, master mode and a long run were not tested.

The driver configured the pulse-per-second pin whenever STM32_ETH_PTP
was set, so a board that uses the timestamp unit without the pin still
had to define GPIO_ETH_PPS_OUT, and the pin was taken away from other
uses. The STM32F4 driver configures the pin with STM32_ETH_PTP_GPIO,
the option meant for it, but that option could not be selected on the
STM32H7, because it depended on the legacy STM32 families.

Configure the pin only with STM32_ETH_PTP_GPIO, and allow that option
on the STM32H7 and STM32H5.

Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Assisted-by: Claude:claude-sonnet-5
The MAC has a system time that is the base of the PTP hardware
timestamps, but the driver never started it, and STM32_ETH_PTP only
printed a warning.

Add the registers of the timestamp unit and start the system time with
the fine update method and the digital rollover, so that the nanoseconds
count up to 10^9. The increment is 2 * 10^9 / HCLK ns, and the addend
makes the update rate half of HCLK, which leaves room to trim the
frequency in both directions. The time starts at zero right after the MAC
reset, not with the MAC configuration, so it does not depend on the PHY
having a link. The reset clears it, so it starts again each time the
interface goes up.

With STM32_ETH_PTP_GPIO, start the pulse-per-second output as a pulse
train with a period of one second and a width of half of it, at the whole
seconds of the system time. The fixed frequency mode of the MAC gives a
pulse too short to be seen, so the flexible mode is used. The interrupt
of the timestamp unit is not enabled in the MAC: it is set each time the
target time of the PPS output is reached and is cleared by reading
MACTSSR, which the interrupt handler does not do, so it would stay
pending and keep the handler running until the network stops.

Register /dev/ptp0 when CONFIG_PTP_CLOCK is set, so that a PTP daemon can
read and set the system time and correct its frequency and its phase.
The frequency is corrected by changing the addend, by up to 50% each way.
A step of the time is added or subtracted with the update register; with
the digital rollover a subtraction is programmed with the negated seconds
and with 10^9 minus the nanoseconds. The pulse train counts by itself, so
it does not follow a step of the system time and would be displaced by the
same amount: after the time is set or stepped, it is started again at the
next whole second.

With HCLK at 200 MHz the system time advanced 10.0018 s while a host
clock advanced 10.002 s, and the pulse train was seen on the pin. Reading,
setting, steps of +0.5 s and -1.25 s and a change of 100 ppm were done
through /dev/ptp0 on hardware, and the edges of the PPS output stayed at
the whole seconds of the system time.

Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Assisted-by: Claude:claude-sonnet-5
The STM32H7 page did not say anything about the Ethernet MAC.

- Describe the time counter of the MAC, the STM32_ETH_PTP option and its
  behavior when the interface goes down.
- Describe the pulse-per-second output and the pins it can use.
- Describe the /dev/ptp0 clock the driver registers and the operations it
  offers, and show a configuration that enables all of it.

Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Assisted-by: Claude:claude-sonnet-5
Add STM32_ETH_TIMESTAMP_RX for the STM32H7, as the one of the legacy
STM32 that provides the timestamp of the frames received.

Timestamp the PTP version 2 messages, over Ethernet and over UDP, except
for the announce, management and signaling messages. The MAC writes the
timestamp in a context descriptor after the last descriptor of the frame.
The driver reads it before giving the frame to the network stack and
passes it in d_rxtime, in the time of the system time of the MAC, the same
as /dev/ptp0. A frame that is not timestamped has a time of zero.

The timestamp goes over the address of the buffer of the context
descriptor, and the code that dropped the context descriptors used a
pointer that was never set. Keep the address of the buffer of each RX
descriptor, and restore it when a context descriptor is given back.

The timestamps of the PTP frames of a grandmaster clock were checked on
hardware against the system time of the MAC, and were within the delay of
the reads.

Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Assisted-by: Claude:claude-sonnet-5
…G loopback

Implement hardware TX timestamping support for STM32 Ethernet MAC
(stm32_eth_m3m4_v1.c) following the upstream SO_TIMESTAMPING loopback
architecture (PR apache#20161).

When an outgoing packet is flagged with SO_TIMESTAMPING (dev->d_iob->io_conn != NULL):
- Clone the IOB and hold a reference in priv->txmeta[txindex]
- Set ETH_TDES0_TTSE on the transmit DMA descriptor
- On transmission completion (stm32_freeframe), retrieve the hardware
  timestamp from TDES6/TDES7, convert to timespec via ptp_to_timespec(),
  and enqueue the clone onto priv->txtstampq
- Deliver pending TX timestamp clones back to netdev RX path in stm32_receive
  using pkt_input(), where net/pkt intercepts the frame and delivers it to
  userspace via recvmsg(..., MSG_ERRQUEUE)
- Properly drain pending queues and clones on interface down (stm32_ifdown)

Assisted-by: Gemini:gemini-3.8-pro
Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Support STM32_ETH_TIMESTAMP_TX on the STM32H7, as the legacy STM32 do,
with the timestamp returned through SO_TIMESTAMPING.

When a packet socket asks for the transmit timestamp of a frame, keep a
copy of the frame and ask the MAC to timestamp it in the descriptor. When
the transmission is done, take the timestamp from the descriptor and give
the copy back to the network stack with it, that delivers it to the error
queue of the socket. The MAC writes the timestamp over the address of the
buffer in the descriptor, so the driver keeps the buffer of these
descriptors. The copies that still wait for their timestamp are released
when the interface goes down.

With a PTP daemon using the peer-to-peer delay mechanism against a
grandmaster clock, the path delay measured was between 9.0 and 9.1 us.

Signed-off-by: Daniel P. Carvalho <danieloak@gmail.com>
Assisted-by: Claude:claude-sonnet-5
@github-actions github-actions Bot added Area: Documentation Improvements or additions to documentation Arch: arm Issues related to ARM (32-bit) architecture Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. labels Sep 20, 2026
@github-actions

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@xiaoxiang781216

Copy link
Copy Markdown
Contributor

@daniel-p-carvalho please fix the conflict

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Area: Documentation Improvements or additions to documentation Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants