Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: phy: aquantia: poll status register

The system interface connection status register is not immediately
correct upon line side link up. This results in the status being read as
OFF and then transitioning to the correct host side link mode with a
short delay. This causes the phylink framework passing the OFF status
down to all MAC config drivers, resulting in the host side link being
misconfigured, which in turn can lead to link flapping or complete
packet loss in some cases.

Mitigate this by periodically polling the register until it not showing
the OFF state. This will be done every 1ms for 10ms, using the same
poll/timeout as the processor intensive operation reads.

If the phy is still expressing the OFF state after the timeout, then set
the link to false and pass the NA interface mode onto the phylink
framework.

Signed-off-by: Aryan Srivastava <aryan.srivastava@alliedtelesis.co.nz>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20241010004935.1774601-1-aryan.srivastava@alliedtelesis.co.nz
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Aryan Srivastava and committed by
Jakub Kicinski
7e5b547c 8401a108

+16 -3
+16 -3
drivers/net/phy/aquantia/aquantia_main.c
··· 42 42 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI 4 43 43 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6 44 44 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI 7 45 + #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OFF 9 45 46 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10 46 47 47 48 #define MDIO_AN_VEND_PROV 0xc400 ··· 349 348 if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE) 350 349 return 0; 351 350 352 - val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS); 353 - if (val < 0) 354 - return val; 351 + /** 352 + * The status register is not immediately correct on line side link up. 353 + * Poll periodically until it reflects the correct ON state. 354 + * Only return fail for read error, timeout defaults to OFF state. 355 + */ 356 + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PHYXS, 357 + MDIO_PHYXS_VEND_IF_STATUS, val, 358 + (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val) != 359 + MDIO_PHYXS_VEND_IF_STATUS_TYPE_OFF), 360 + AQR107_OP_IN_PROG_SLEEP, 361 + AQR107_OP_IN_PROG_TIMEOUT, false); 362 + if (ret && ret != -ETIMEDOUT) 363 + return ret; 355 364 356 365 switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) { 357 366 case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR: ··· 388 377 case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII: 389 378 phydev->interface = PHY_INTERFACE_MODE_2500BASEX; 390 379 break; 380 + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OFF: 391 381 default: 382 + phydev->link = false; 392 383 phydev->interface = PHY_INTERFACE_MODE_NA; 393 384 break; 394 385 }