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

net: phy: adin: allow control of Fast Link Down

Add support to allow Fast Link Down (aka "Enhanced link detection") to
be controlled via the ETHTOOL_PHY_FAST_LINK_DOWN tunable. These PHYs
have this feature enabled by default.

Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com>
Acked-by: Nuno Sa <nuno.sa@analog.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20231127-adin-fld-v1-1-797f6423fd48@axis.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Vincent Whitchurch and committed by
Jakub Kicinski
cb2f01b8 127532cd

+53
+53
drivers/net/phy/adin.c
··· 68 68 #define ADIN1300_EEE_CAP_REG 0x8000 69 69 #define ADIN1300_EEE_ADV_REG 0x8001 70 70 #define ADIN1300_EEE_LPABLE_REG 0x8002 71 + 72 + #define ADIN1300_FLD_EN_REG 0x8E27 73 + #define ADIN1300_FLD_PCS_ERR_100_EN BIT(7) 74 + #define ADIN1300_FLD_PCS_ERR_1000_EN BIT(6) 75 + #define ADIN1300_FLD_SLCR_OUT_STUCK_100_EN BIT(5) 76 + #define ADIN1300_FLD_SLCR_OUT_STUCK_1000_EN BIT(4) 77 + #define ADIN1300_FLD_SLCR_IN_ZDET_100_EN BIT(3) 78 + #define ADIN1300_FLD_SLCR_IN_ZDET_1000_EN BIT(2) 79 + #define ADIN1300_FLD_SLCR_IN_INVLD_100_EN BIT(1) 80 + #define ADIN1300_FLD_SLCR_IN_INVLD_1000_EN BIT(0) 81 + /* These bits are the ones which are enabled by default. */ 82 + #define ADIN1300_FLD_EN_ON \ 83 + (ADIN1300_FLD_SLCR_OUT_STUCK_100_EN | \ 84 + ADIN1300_FLD_SLCR_OUT_STUCK_1000_EN | \ 85 + ADIN1300_FLD_SLCR_IN_ZDET_100_EN | \ 86 + ADIN1300_FLD_SLCR_IN_ZDET_1000_EN | \ 87 + ADIN1300_FLD_SLCR_IN_INVLD_1000_EN) 88 + 71 89 #define ADIN1300_CLOCK_STOP_REG 0x9400 72 90 #define ADIN1300_LPI_WAKE_ERR_CNT_REG 0xa000 73 91 ··· 434 416 val); 435 417 } 436 418 419 + static int adin_get_fast_down(struct phy_device *phydev, u8 *msecs) 420 + { 421 + int reg; 422 + 423 + reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_FLD_EN_REG); 424 + if (reg < 0) 425 + return reg; 426 + 427 + if (reg & ADIN1300_FLD_EN_ON) 428 + *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_ON; 429 + else 430 + *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF; 431 + 432 + return 0; 433 + } 434 + 435 + static int adin_set_fast_down(struct phy_device *phydev, const u8 *msecs) 436 + { 437 + if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_ON) 438 + return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, 439 + ADIN1300_FLD_EN_REG, 440 + ADIN1300_FLD_EN_ON); 441 + 442 + if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) 443 + return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 444 + ADIN1300_FLD_EN_REG, 445 + ADIN1300_FLD_EN_ON); 446 + 447 + return -EINVAL; 448 + } 449 + 437 450 static int adin_get_tunable(struct phy_device *phydev, 438 451 struct ethtool_tunable *tuna, void *data) 439 452 { ··· 473 424 return adin_get_downshift(phydev, data); 474 425 case ETHTOOL_PHY_EDPD: 475 426 return adin_get_edpd(phydev, data); 427 + case ETHTOOL_PHY_FAST_LINK_DOWN: 428 + return adin_get_fast_down(phydev, data); 476 429 default: 477 430 return -EOPNOTSUPP; 478 431 } ··· 488 437 return adin_set_downshift(phydev, *(const u8 *)data); 489 438 case ETHTOOL_PHY_EDPD: 490 439 return adin_set_edpd(phydev, *(const u16 *)data); 440 + case ETHTOOL_PHY_FAST_LINK_DOWN: 441 + return adin_set_fast_down(phydev, data); 491 442 default: 492 443 return -EOPNOTSUPP; 493 444 }