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 */
