arch/arm/stm32h7: poll MDIO completion in microseconds, not 5 ms steps - #20067
Merged
Conversation
stm32_c22_read() and stm32_c22_write() waited for the MACMDIOAR busy bit with up_mdelay(5) between checks. A Clause 22 frame takes about 30 us, so the first check always sees the bus busy and every PHY register access costs a 5 ms busy-wait, roughly 150 times the transfer. stm32_phyinit() waits for link-up with PHY_RETRY_TIMEOUT (6552) MSR reads. With no cable attached that is 33 s of CPU spent in up_mdelay() inside ifup, with the network lock held: on an STM32H753 the netinit thread pinned the core at 44% for the first 65 s after boot and every socket operation on other threads blocked until it gave up. Before the MDIO bus refactor, stm32_phyread() polled the busy bit in a tight loop. Poll every 10 us instead, with the timeout expressed in microseconds so the total bound stays at 10 ms, and report the timeout from the result rather than the loop counter so a transfer that completes on the last iteration is not logged as timed out. Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
xiaoxiang781216
approved these changes
Sep 7, 2026
acassis
approved these changes
Sep 7, 2026
dakejahl
added a commit
to PX4/PX4-Autopilot
that referenced
this pull request
Sep 7, 2026
Every PHY register access on STM32H7 spent 5 ms in up_mdelay(), so the boot-time autonegotiation link wait ran netinit at 44% CPU for 65 s with the net lock held whenever no ethernet cable was attached (PX4/NuttX#414, apache/nuttx#20067). Also picks up the two upstream stm32_mdio fixes for the lower-half cast and the Clause 22 write register field.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
stm32_c22_read()/stm32_c22_write()inarch/arm/src/stm32h7/stm32_mdio.cwait for the MACMDIOAR busy bit withup_mdelay(5)between checks. A Clause 22 frame is ~30 us at a 2.5 MHz MDC, so the first check always sees the bus busy and every PHY register access costs a 5 ms busy-wait. Before the MDIO bus refactor (95efa6f)stm32_phyread()polled the busy bit in a tight loop.The cost shows up in
stm32_phyinit(), which waits for link-up withPHY_RETRY_TIMEOUT(6552) MSR reads whenSTM32H7_AUTONEGis set. With no cable attached,ifupspends ~33 s of CPU inup_mdelay()with the network lock held. On an STM32H753 running PX4 thenetinitmonitor thread pinned the core at 44% for the first 65 s after boot (priority-inherited to 100 because a UDP sender was blocked on the net lock), and every socket operation on other threads stalled until the link wait timed out.This polls every 10 us instead, with the timeout expressed in microseconds so the total bound stays at 10 ms, and reports a timeout from the result rather than the loop counter so a transfer completing on the last iteration is not logged as timed out.
Impact
STM32H7 boards with
STM32H7_ETHMAC. PHY register access goes from a fixed 5 ms to ~30 us; the autonegotiation link wait with no cable drops from ~33 s of CPU to under a second of mostly sleeping. No functional change when the PHY responds.Testing
Host: Linux, GCC 13.2.1. Board: ARK FMU-V6X (STM32H753, LAN8742A PHY,
CONFIG_STM32H7_AUTONEG=y,CONFIG_STM32H7_PHY_POLLING=y,CONFIG_NETINIT_MONITOR=y), no ethernet cable, running PX4 on NuttX 12.12.0 with this change cherry-picked.top oncesampled every 2 s from power-on over the debug console.Before (netinit at 44% until ~65 s uptime, priority 100 inherited from a blocked UDP sender, then 0.44% = one 5 ms MDIO read per 2 s poll):
After:
Timestamps are seconds since power-on; the board reaches the shell at ~12 s. The UDP MAVLink instance that was blocked on the net lock for 65 s now proceeds at ~2 s.
tools/checkpatch.sh -c -u -m -g origin/master..HEADpasses.