From: Selvamani Rajagopal Adding loopback support for S2500 internal PHY to help running loopback test through ethtool. This instance requires only manipulating the loopback bit in the PHY only. So, added a generic helper function to modify loopback bit of the PHY without modifying any other bit. This will help the PHYs that may have fixed speed, like 10Base-T1S or PHYs that don't need any other settings to set them in loopback mode. Signed-off-by: Selvamani Rajagopal --- changes in v8 - No code change. Changes were in two different patches. Merged into one. changes in v7 - No change changes in v6 - No change changes in v5 - No change changes in v4 - Moved the onsemi implementation to a new, genphy API to make it vendor agnostic. changes in v3 - Addd loopback functionality for onsemi's PHY driver - First patch --- drivers/net/phy/dp83867.c | 11 +---------- drivers/net/phy/ncn26000.c | 1 + drivers/net/phy/phy_device.c | 20 ++++++++++++++++++++ include/linux/phy.h | 2 ++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index a3cd5cb11ea0..38c17a68cf26 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -1058,15 +1058,6 @@ static void dp83867_link_change_notify(struct phy_device *phydev) } } -static int dp83867_loopback(struct phy_device *phydev, bool enable, int speed) -{ - if (enable && speed) - return -EOPNOTSUPP; - - return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, - enable ? BMCR_LOOPBACK : 0); -} - static int dp83867_led_brightness_set(struct phy_device *phydev, u8 index, enum led_brightness brightness) @@ -1292,7 +1283,7 @@ static struct phy_driver dp83867_driver[] = { .resume = dp83867_resume, .link_change_notify = dp83867_link_change_notify, - .set_loopback = dp83867_loopback, + .set_loopback = genphy_loopback_fixed_speed, .led_brightness_set = dp83867_led_brightness_set, .led_hw_is_supported = dp83867_led_hw_is_supported, diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c index b362e85c7911..933cba6d00b5 100644 --- a/drivers/net/phy/ncn26000.c +++ b/drivers/net/phy/ncn26000.c @@ -178,6 +178,7 @@ static struct phy_driver ncn26000_driver[] = { .config_aneg = ncn26000_config_aneg, .read_status = ncn26000_read_status, .handle_interrupt = ncn26000_handle_interrupt, + .set_loopback = genphy_loopback_fixed_speed, .set_plca_cfg = ncn26000_c45_plca_set_cfg, .get_plca_cfg = genphy_c45_plca_get_cfg, .get_plca_status = genphy_c45_plca_get_status, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 5b13a74e2fa9..ca438d4e8fcb 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2775,6 +2775,26 @@ int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, } EXPORT_SYMBOL(genphy_write_mmd_unsupported); +/** + * genphy_loopback_fixed_speed - Helper to modify the PHY loopback mode + * without affecting any other settings. + * @phydev: The phy_device struct + * @enable: Flag to enable or disable the PHY level loopback. + * @speed: Speed setting. Not expected to be set. Error if it is set. + * + * Returns: 0 if successful, negative error code on failure. + */ +int genphy_loopback_fixed_speed(struct phy_device *phydev, bool enable, + int speed) +{ + if (enable && speed) + return -EOPNOTSUPP; + + return phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK, + enable ? BMCR_LOOPBACK : 0); +} +EXPORT_SYMBOL(genphy_loopback_fixed_speed); + int genphy_suspend(struct phy_device *phydev) { return phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); diff --git a/include/linux/phy.h b/include/linux/phy.h index 7c5098a0dd6c..c1b9bc305c82 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -2327,6 +2327,8 @@ int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, u16 regnum); int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, u16 regnum, u16 val); +int genphy_loopback_fixed_speed(struct phy_device *phydev, bool enable, + int speed); /* Clause 37 */ int genphy_c37_config_aneg(struct phy_device *phydev); -- 2.43.0