This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 8c8ef5fbccd963e52688a4d984e3be78dff1ca3d
Author: Jorge Guzman <[email protected]>
AuthorDate: Thu Aug 6 07:24:59 2026 -0300

    stm32h7/ethernet: allow restricting autonegotiation to 10BASE-T full duplex
    
    On the linum-stm32h753bi, Ethernet throughput collapses in proportion to
    what the display panel is showing. With the LTDC scanning a black screen
    a 1.2 MiB TCP transfer to a wired peer takes 0.7 s; solid white takes 20
    to 55 s and noise over 130 s, all at the same negotiated 100BASE-TX full
    duplex, with the same bytes read from the same SDRAM. The display's
    switching couples into the PHY hard enough to corrupt 100BASE-TX
    signalling, and TCP grinds through the losses at whatever rate survives.
    
    10BASE-T signals at 2.5 V with Manchester coding at a tenth of the
    frequency, and does not care: black, white and noise all move at the
    link rate. The same transfer that took five minutes with the display
    rendering takes 5.6 seconds.
    
    Restricting the ANAR advertisement is deliberately not the same as
    disabling autonegotiation. A forced MCR leaves the partner to parallel
    detection, which cannot sense duplex and picks half, a genuine
    mismatch, verified here to stall bulk traffic completely. Advertising
    only 10BASE-T full duplex keeps the negotiation and lands both ends on
    the same mode.
    
    Also fix the never-compiled !CONFIG_STM32_AUTONEG path, which still
    called stm32_phywrite(); this driver has only ever had mdio_write().
    And say what was negotiated at link-up: a duplex mismatch looks exactly
    like a bad cable, and nothing else reports which of the two it is.
    
    The vnc configuration of the linum board enables the new option, and its
    packet pool sizing from a few commits ago stays: at any link speed, 24
    buffers of 196 bytes was never going to stream a display.
    
    
    Assisted-by: Claude:opus-5
    Signed-off-by: Jorge Guzman <[email protected]>
---
 arch/arm/src/common/stm32/Kconfig.eth | 21 +++++++++++++++++++
 arch/arm/src/stm32h7/stm32_ethernet.c | 39 +++++++++++++++++++++++++++++------
 2 files changed, 54 insertions(+), 6 deletions(-)

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 <string.h>
 #include <assert.h>
 #include <nuttx/debug.h>
+#include <syslog.h>
 #include <errno.h>
 
 #include <sys/param.h>
@@ -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;
 }

Reply via email to