From: Konrad Knitter <[email protected]>
The ethtool setter uses the link-partner AN ability bit to decide whether a
request to disable autonegotiation can be handled. That bit is valid only
while the link is up, so a link-down request skips the configuration update
and returns success.
Allow link-down requests through to PHY capability validation. On legacy
MACs, retain the existing restriction for PHYs that advertise autoneg.
Generic MACs configure Clause 37 through low_power_ctrl_an, and must keep
AUTO_LINK_UPDT set so firmware applies the change. Handle that field for
both enable and disable requests.
Fixes: 48cb27f2fd18 ("ice: Implement handlers for ethtool PHY/link operations")
Signed-off-by: Konrad Knitter <[email protected]>
Signed-off-by: Aleksandr Loktionov <[email protected]>
---
Changes since v3:
- Allow link-down disable requests without relying on stale partner state.
- Keep the generic-MAC enable bypass; validate E830 Autoneg support before
restoring Clause 37 when its cached bit is clear.
- Avoid marking unchanged Clause 37 requests as autoneg changes.
- Correct the Fixes tag to the commit that introduced the ethtool handler.
drivers/net/ethernet/intel/ice/ice_ethtool.c | 57 +++++++++++++++++++-
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c
b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 8b7d7be..080a65a 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -2510,6 +2510,28 @@ ice_ksettings_find_adv_link_speed(const struct
ethtool_link_ksettings *ks)
return adv_link_speed;
}
+/**
+ * ice_autoneg_disable_allowed - check if autoneg can be disabled
+ * @p: port info
+ *
+ * Check if autonegotiation can be disabled based on link state.
+ * ICE_AQ_LP_AN_ABILITY is only valid when the link is up, so let the
+ * MAC-specific handling below decide whether a link-down request is supported.
+ *
+ * Return: true if autoneg has completed, the link is down, or the link
+ * partner does not advertise autonegotiation capability.
+ */
+static bool ice_autoneg_disable_allowed(struct ice_port_info *p)
+{
+ u8 an_info = p->phy.link_info.an_info;
+
+ if (an_info & ICE_AQ_AN_COMPLETED)
+ return true;
+ /* ICE_AQ_LP_AN_ABILITY is only valid when link is up */
+ return !(p->phy.link_info.link_info & ICE_AQ_LINK_UP) ||
+ !(an_info & ICE_AQ_LP_AN_ABILITY);
+}
+
/**
* ice_setup_autoneg
* @p: port info
@@ -2535,12 +2557,31 @@ ice_setup_autoneg(struct ice_port_info *p, struct
ethtool_link_ksettings *ks,
if (autoneg_enabled == AUTONEG_ENABLE) {
/* If autoneg was not already enabled */
if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) {
+ if (ice_is_generic_mac(p->hw)) {
+ if (!(config->low_power_ctrl_an &
+ ICE_AQC_PHY_AN_EN_CLAUSE37)) {
+ config->low_power_ctrl_an |=
+ ICE_AQC_PHY_AN_EN_CLAUSE37;
+ config->caps |=
+ ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+ *autoneg_changed = 1;
+ }
+ return 0;
+ }
/* If autoneg is not supported, return error */
if (!ethtool_link_ksettings_test_link_mode(ks,
supported,
Autoneg)) {
netdev_info(netdev, "Autoneg not supported on
this phy.\n");
err = -EINVAL;
+ } else if (p->hw->mac_type == ICE_MAC_E830) {
+ if (!(config->low_power_ctrl_an &
+ ICE_AQC_PHY_AN_EN_CLAUSE37)) {
+ config->low_power_ctrl_an |=
+ ICE_AQC_PHY_AN_EN_CLAUSE37;
+ config->caps |=
ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+ *autoneg_changed = 1;
+ }
} else {
/* Autoneg is allowed to change */
config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
@@ -2548,8 +2589,20 @@ ice_setup_autoneg(struct ice_port_info *p, struct
ethtool_link_ksettings *ks,
}
}
} else {
- /* If autoneg is currently enabled */
- if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) {
+ /* If autoneg completed or link partner does not support AN */
+ if (ice_autoneg_disable_allowed(p)) {
+ if (ice_is_generic_mac(p->hw) ||
+ p->hw->mac_type == ICE_MAC_E830) {
+ if (config->low_power_ctrl_an &
+ ICE_AQC_PHY_AN_EN_CLAUSE37) {
+ config->low_power_ctrl_an &=
+ ~ICE_AQC_PHY_AN_EN_CLAUSE37;
+ config->caps |=
+ ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+ *autoneg_changed = 1;
+ }
+ return 0;
+ }
/* If autoneg is supported 10GBASE_T is the only PHY
* that can disable it, so otherwise return error
*/
--
2.52.0