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

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

commit e7ec62e24bbdb259374e059f17189db7697831e1
Author: raiden00pl <[email protected]>
AuthorDate: Tue Oct 13 11:29:05 2026 +0200

    drivers/net/igb: Restart PHY auto-negotiation when enabling the device.
    
    After CTRL.RST the link comes up only when auto-negotiation completes.
    Restart it through MDIC in igb_enable().  Fixes carrier after
    ifdown/ifup, and at boot on QEMU >= 9.0.
    
    Assisted-by: Claude:claude-opus-5-5
    Signed-off-by: raiden00pl <[email protected]>
---
 drivers/net/igb.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/igb.h | 14 +++++++++++
 2 files changed, 85 insertions(+)

diff --git a/drivers/net/igb.c b/drivers/net/igb.c
index 9294a166c57..8b872fb92d3 100644
--- a/drivers/net/igb.c
+++ b/drivers/net/igb.c
@@ -36,6 +36,7 @@
 #include <nuttx/addrenv.h>
 #include <nuttx/spinlock.h>
 
+#include <nuttx/net/mii.h>
 #include <nuttx/net/netdev_lowerhalf.h>
 #include <nuttx/pci/pci.h>
 #include <nuttx/net/igb.h>
@@ -1184,6 +1185,70 @@ static void igb_phy_reset(FAR struct igb_driver_s *priv)
   up_udelay(100);
 }
 
+/*****************************************************************************
+ * Name: igb_mdic
+ *
+ * Description:
+ *   Run one MDI read or write cycle on the internal PHY.
+ *
+ *****************************************************************************/
+
+static int igb_mdic(FAR struct igb_driver_s *priv, uint32_t op, int reg,
+                    FAR uint16_t *data)
+{
+  uint32_t regval;
+  int      i;
+
+  igb_putreg_mem(priv, IGB_MDIC,
+                 op | (IGB_PHY_ADDR << IGB_MDIC_PHYADD_SHIFT) |
+                 (reg << IGB_MDIC_REGADD_SHIFT) | *data);
+
+  for (i = 0; i < 1000; i++)
+    {
+      regval = igb_getreg_mem(priv, IGB_MDIC);
+      if (regval & IGB_MDIC_READY)
+        {
+          if (regval & IGB_MDIC_ERROR)
+            {
+              return -EIO;
+            }
+
+          *data = regval & IGB_MDIC_DATA_MASK;
+          return OK;
+        }
+
+      up_udelay(50);
+    }
+
+  return -ETIMEDOUT;
+}
+
+/*****************************************************************************
+ * Name: igb_phy_autoneg
+ *
+ * Description:
+ *   Restart PHY auto-negotiation.
+ *
+ *****************************************************************************/
+
+static void igb_phy_autoneg(FAR struct igb_driver_s *priv)
+{
+  uint16_t bmcr = 0;
+  int      ret;
+
+  ret = igb_mdic(priv, IGB_MDIC_OP_READ, MII_MCR, &bmcr);
+  if (ret == OK)
+    {
+      bmcr |= MII_MCR_ANENABLE | MII_MCR_ANRESTART;
+      ret = igb_mdic(priv, IGB_MDIC_OP_WRITE, MII_MCR, &bmcr);
+    }
+
+  if (ret != OK)
+    {
+      nerr("PHY auto-negotiation restart failed %d\n", ret);
+    }
+}
+
 /*****************************************************************************
  * Name: igb_enable
  *
@@ -1271,6 +1336,12 @@ static void igb_enable(FAR struct igb_driver_s *priv)
 
   igb_putreg_mem(priv, IGB_CTRL, IGB_CTRL_SLU);
 
+  /* Restart auto-negotiation.  The link comes up when it completes,
+   * signalled by the link status change interrupt.
+   */
+
+  igb_phy_autoneg(priv);
+
   /* Setup and enable Transmitter */
 
   regval = igb_getreg_mem(priv, IGB_TCTL);
diff --git a/drivers/net/igb.h b/drivers/net/igb.h
index 7292d395723..676eea382bf 100644
--- a/drivers/net/igb.h
+++ b/drivers/net/igb.h
@@ -309,6 +309,20 @@
 #define IGB_CTRL_VME              (1 << 30)  /* Bit 30: VLAN Mode Enable */
 #define IGB_CTRL_PHYRST           (1 << 31)  /* Bit 31: PHY Reset */
 
+/* MDI Control Register */
+
+#define IGB_MDIC_DATA_MASK        (0xffff)   /* Bits 0-15: Data */
+#define IGB_MDIC_REGADD_SHIFT     (16)       /* Bits 16-20: PHY register 
address */
+#define IGB_MDIC_PHYADD_SHIFT     (21)       /* Bits 21-25: PHY address */
+#define IGB_MDIC_OP_WRITE         (1 << 26)  /* Bits 26-27: 01b: MDI write */
+#define IGB_MDIC_OP_READ          (2 << 26)  /* Bits 26-27: 10b: MDI read */
+#define IGB_MDIC_READY            (1 << 28)  /* Bit 28: Ready */
+#define IGB_MDIC_ERROR            (1 << 30)  /* Bit 30: Error */
+
+/* Address of the internal copper PHY */
+
+#define IGB_PHY_ADDR              (1)
+
 /* Device Status Regiuster */
 
 #define IGB_STATUS_FD             (1 << 0)   /* Bit 0: Full Duplex */

Reply via email to