Allow PHY drivers to hook the .get_features() method to disable EEE support. This is useful for TI PHYs, where we have a statement that none of their gigabit products support EEE, yet at least DP83867 reports EEE capabilties and implements EEE negotiation. Signed-off-by: Russell King (Oracle) --- drivers/net/phy/phy-core.c | 2 -- drivers/net/phy/phy_device.c | 34 ++++++++++++++++++++++++++++++---- include/linux/phy.h | 1 + 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 605ca20ae192..43ccbd3a09f8 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -207,8 +207,6 @@ void of_set_phy_eee_broken(struct phy_device *phydev) if (!IS_ENABLED(CONFIG_OF_MDIO) || !node) return; - linkmode_zero(modes); - if (of_property_read_bool(node, "eee-broken-100tx")) linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, modes); if (of_property_read_bool(node, "eee-broken-1000t")) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 81984d4ebb7c..437b89a0e944 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -3397,6 +3397,34 @@ struct fwnode_handle *fwnode_get_phy_node(const struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_get_phy_node); +static int phy_get_features(struct phy_device *phydev) +{ + int err; + + if (phydev->is_c45) + err = genphy_c45_pma_read_abilities(phydev); + else + err = genphy_read_abilities(phydev); + + return err; +} + +/** + * phy_get_Features_no_eee - read the PHY features, disabling all EEE + * @phydev: phy_device structure to be added to the MDIO bus + * + * Read the PHY features, and fill the @phydev->eee_disabled_modes to + * prevent EEE being used. This is intended to be used for PHY .get_feature + * methods where a PHY reports incorrect capabilities. + */ +int phy_get_features_no_eee(struct phy_device *phydev) +{ + linkmode_fill(phydev->eee_disabled_modes); + + return phy_get_features(phydev); +} +EXPORT_SYMBOL_GPL(phy_get_features_no_eee); + /** * phy_probe - probe and init a PHY device * @dev: device to probe and init @@ -3442,10 +3470,8 @@ static int phy_probe(struct device *dev) } else if (phydrv->get_features) err = phydrv->get_features(phydev); - else if (phydev->is_c45) - err = genphy_c45_pma_read_abilities(phydev); - else - err = genphy_read_abilities(phydev); + else + err = phy_get_features(phydev); if (err) goto out; diff --git a/include/linux/phy.h b/include/linux/phy.h index bf5457341ca8..2655c0ae6488 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -2299,6 +2299,7 @@ void phy_support_sym_pause(struct phy_device *phydev); void phy_support_asym_pause(struct phy_device *phydev); void phy_support_eee(struct phy_device *phydev); void phy_disable_eee(struct phy_device *phydev); +int phy_get_features_no_eee(struct phy_device *phydev); void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx, bool autoneg); void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx); -- 2.47.3 As TI Gigabit PHYs do not support EEE, use the newly introduced phy_get_features_no_eee() to read the features but mark EEE as disabled. Signed-off-by: Russell King (Oracle) --- drivers/net/phy/dp83822.c | 3 +++ drivers/net/phy/dp83867.c | 1 + drivers/net/phy/dp83869.c | 1 + drivers/net/phy/dp83tc811.c | 1 + 4 files changed, 6 insertions(+) diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index 33db21251f2e..20caf9a5faa7 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -1160,6 +1160,7 @@ static int dp83822_led_hw_control_get(struct phy_device *phydev, u8 index, .name = (_name), \ /* PHY_BASIC_FEATURES */ \ .probe = dp83822_probe, \ + .get_features = phy_get_features_no_eee, \ .soft_reset = dp83822_phy_reset, \ .config_init = dp83822_config_init, \ .read_status = dp83822_read_status, \ @@ -1180,6 +1181,7 @@ static int dp83822_led_hw_control_get(struct phy_device *phydev, u8 index, .name = (_name), \ /* PHY_BASIC_FEATURES */ \ .probe = dp8382x_probe, \ + .get_features = phy_get_features_no_eee, \ .soft_reset = dp83822_phy_reset, \ .config_init = dp83825_config_init, \ .get_wol = dp83822_get_wol, \ @@ -1196,6 +1198,7 @@ static int dp83822_led_hw_control_get(struct phy_device *phydev, u8 index, .name = (_name), \ /* PHY_BASIC_FEATURES */ \ .probe = dp83826_probe, \ + .get_features = phy_get_features_no_eee, \ .soft_reset = dp83822_phy_reset, \ .config_init = dp83826_config_init, \ .get_wol = dp83822_get_wol, \ diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 36a0c1b7f59c..da055ff861be 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -1124,6 +1124,7 @@ static struct phy_driver dp83867_driver[] = { /* PHY_GBIT_FEATURES */ .probe = dp83867_probe, + .get_features = phy_get_features_no_eee, .config_init = dp83867_config_init, .soft_reset = dp83867_phy_reset, diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 1f381d7b13ff..4400654b0f72 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -906,6 +906,7 @@ static int dp83869_phy_reset(struct phy_device *phydev) PHY_ID_MATCH_MODEL(_id), \ .name = (_name), \ .probe = dp83869_probe, \ + .get_features = phy_get_features_no_eee, \ .config_init = dp83869_config_init, \ .soft_reset = dp83869_phy_reset, \ .config_intr = dp83869_config_intr, \ diff --git a/drivers/net/phy/dp83tc811.c b/drivers/net/phy/dp83tc811.c index e480c2a07450..92c5f3cfee9e 100644 --- a/drivers/net/phy/dp83tc811.c +++ b/drivers/net/phy/dp83tc811.c @@ -390,6 +390,7 @@ static struct phy_driver dp83811_driver[] = { .phy_id_mask = 0xfffffff0, .name = "TI DP83TC811", /* PHY_BASIC_FEATURES */ + .get_features = phy_get_features_no_eee, .config_init = dp83811_config_init, .config_aneg = dp83811_config_aneg, .soft_reset = dp83811_phy_reset, -- 2.47.3