diff --git a/arch/arm/src/common/stm32/Kconfig.eth b/arch/arm/src/common/stm32/Kconfig.eth index e90f665e08d..7a5359fa578 100644 --- a/arch/arm/src/common/stm32/Kconfig.eth +++ b/arch/arm/src/common/stm32/Kconfig.eth @@ -52,6 +52,27 @@ endif # !STM32_AUTONEG if STM32_AUTONEG +config STM32_AUTONEG_10FD_ONLY + bool "Advertise only 10BASE-T full duplex" + default n + ---help--- + Restrict the autonegotiation advertisement to 10BASE-T full + duplex, so that both ends negotiate that and nothing else. + + The reason to want this is electrical, not economic. 100BASE-TX + signalling sits at about 1 V with MLT-3 coding; 10BASE-T uses + 2.5 V Manchester at a tenth of the frequency, and shrugs off + interference that corrupts 100BASE-TX outright. On a board + where another subsystem couples noise into the PHY -- a parallel + RGB display sharing the board with the magnetics, say -- a + clean 10 Mbps link outperforms a 100 Mbps one that is losing + frames to bit errors. + + Restricting the advertisement is not the same as disabling + autonegotiation: a forced MCR leaves the partner to parallel + detection, which cannot detect duplex and will pick half -- + a genuine mismatch that stalls bulk traffic completely. + config STM32_PHYSR int "PHY Status Register Address (decimal)" ---help--- diff --git a/arch/arm/src/stm32h7/stm32_ethernet.c b/arch/arm/src/stm32h7/stm32_ethernet.c index 42316f522fb..26bba57c59b 100644 --- a/arch/arm/src/stm32h7/stm32_ethernet.c +++ b/arch/arm/src/stm32h7/stm32_ethernet.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -3370,10 +3371,26 @@ static int stm32_phyinit(struct stm32_ethmac_s *priv) return -ETIMEDOUT; } - /* Enable auto-negotiation */ +#ifdef CONFIG_STM32_AUTONEG_10FD_ONLY + /* Advertise only 10BASE-T full duplex, so that negotiation lands + * there on both ends. See the help text of the option for why a + * board would want a slower link on purpose. + */ + + ret = mdio_write(priv->mdio, CONFIG_STM32_PHYADDR, MII_ADVERTISE, + MII_ADVERTISE_10BASETXFULL | MII_ADVERTISE_CSMA); + if (ret < 0) + { + nerr("ERROR: Failed to write the PHY ANAR: %d\n", ret); + return ret; + } +#endif + + /* Enable and restart auto-negotiation */ ret = mdio_write(priv->mdio, - CONFIG_STM32_PHYADDR, MII_MCR, MII_MCR_ANENABLE); + CONFIG_STM32_PHYADDR, MII_MCR, + MII_MCR_ANENABLE | MII_MCR_ANRESTART); if (ret < 0) { nerr("ERROR: Failed to enable auto-negotiation: %d\n", ret); @@ -3483,7 +3500,12 @@ static int stm32_phyinit(struct stm32_ethmac_s *priv) phyval |= MII_MCR_SPEED100; #endif - ret = stm32_phywrite(CONFIG_STM32_PHYADDR, MII_MCR, phyval, 0xffff); + /* mdio_write, not stm32_phywrite: this driver never had the latter. + * The call was carried over from the F7 driver and nothing had ever + * built this path. + */ + + ret = mdio_write(priv->mdio, CONFIG_STM32_PHYADDR, MII_MCR, phyval); if (ret < 0) { nerr("ERROR: Failed to write the PHY MCR: %d\n", ret); @@ -3502,9 +3524,14 @@ static int stm32_phyinit(struct stm32_ethmac_s *priv) #endif #endif - ninfo("Duplex: %s Speed: %d MBps\n", - priv->fduplex ? "FULL" : "HALF", - priv->mbps100 ? 100 : 10); + /* Diagnostic: say what was negotiated even without net debug. A + * duplex mismatch looks exactly like a bad cable and nothing else + * says which of the two it is. + */ + + syslog(LOG_INFO, "stm32_eth: link %s-duplex %d Mbps\n", + priv->fduplex ? "full" : "half", + priv->mbps100 ? 100 : 10); return OK; }