emac_set_pauseparam (the set_pauseparam callback) didn't properly update phydev->advertising. Fix it by changing it to call phy_set_asym_pause. Also simplify/reorganize related code around this. Fixes: bfec6d7f2001 ("net: spacemit: Add K1 Ethernet MAC") Signed-off-by: Vivian Wang --- drivers/net/ethernet/spacemit/k1_emac.c | 48 ++++++++++++++------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/spacemit/k1_emac.c b/drivers/net/ethernet/spacemit/k1_emac.c index e1c5faff3b71..61d62c0f028e 100644 --- a/drivers/net/ethernet/spacemit/k1_emac.c +++ b/drivers/net/ethernet/spacemit/k1_emac.c @@ -133,7 +133,6 @@ struct emac_priv { u32 rx_delay; bool flow_control_autoneg; - u8 flow_control; /* Softirq-safe, hold while touching hardware statistics */ spinlock_t stats_lock; @@ -1039,14 +1038,7 @@ static void emac_set_rx_fc(struct emac_priv *priv, bool enable) emac_wr(priv, MAC_FC_CONTROL, val); } -static void emac_set_fc(struct emac_priv *priv, u8 fc) -{ - emac_set_tx_fc(priv, fc & FLOW_CTRL_TX); - emac_set_rx_fc(priv, fc & FLOW_CTRL_RX); - priv->flow_control = fc; -} - -static void emac_set_fc_autoneg(struct emac_priv *priv) +static void emac_set_fc(struct emac_priv *priv) { struct phy_device *phydev = priv->ndev->phydev; u32 local_adv, remote_adv; @@ -1056,17 +1048,18 @@ static void emac_set_fc_autoneg(struct emac_priv *priv) remote_adv = 0; - if (phydev->pause) + /* Force settings in advertising if autoneg disabled */ + + if (!priv->flow_control_autoneg || phydev->pause) remote_adv |= LPA_PAUSE_CAP; - if (phydev->asym_pause) + if (!priv->flow_control_autoneg || phydev->asym_pause) remote_adv |= LPA_PAUSE_ASYM; fc = mii_resolve_flowctrl_fdx(local_adv, remote_adv); - priv->flow_control_autoneg = true; - - emac_set_fc(priv, fc); + emac_set_tx_fc(priv, fc & FLOW_CTRL_TX); + emac_set_rx_fc(priv, fc & FLOW_CTRL_RX); } /* @@ -1429,31 +1422,28 @@ static void emac_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause) { struct emac_priv *priv = netdev_priv(dev); + u32 val = emac_rd(priv, MAC_FC_CONTROL); pause->autoneg = priv->flow_control_autoneg; - pause->tx_pause = !!(priv->flow_control & FLOW_CTRL_TX); - pause->rx_pause = !!(priv->flow_control & FLOW_CTRL_RX); + pause->tx_pause = !!(val & MREGBIT_FC_GENERATION_ENABLE); + pause->rx_pause = !!(val & MREGBIT_FC_DECODE_ENABLE); } static int emac_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause) { struct emac_priv *priv = netdev_priv(dev); - u8 fc = 0; + struct phy_device *phydev = dev->phydev; - priv->flow_control_autoneg = pause->autoneg; + if (!phydev) + return -ENODEV; - if (pause->autoneg) { - emac_set_fc_autoneg(priv); - } else { - if (pause->tx_pause) - fc |= FLOW_CTRL_TX; + if (!phy_validate_pause(phydev, pause)) + return -EINVAL; - if (pause->rx_pause) - fc |= FLOW_CTRL_RX; + priv->flow_control_autoneg = pause->autoneg; - emac_set_fc(priv, fc); - } + phy_set_asym_pause(dev->phydev, pause->rx_pause, pause->tx_pause); return 0; } @@ -1632,7 +1622,7 @@ static void emac_adjust_link(struct net_device *dev) emac_wr(priv, MAC_GLOBAL_CONTROL, ctrl); - emac_set_fc_autoneg(priv); + emac_set_fc(priv); } phy_print_status(phydev); @@ -2010,6 +2000,8 @@ static int emac_probe(struct platform_device *pdev) priv->pdev = pdev; platform_set_drvdata(pdev, priv); + priv->flow_control_autoneg = true; + ret = emac_config_dt(pdev, priv); if (ret < 0) return dev_err_probe(dev, ret, "Configuration failed\n"); --- base-commit: cb6649f6217c0331b885cf787f1d175963e2a1d2 change-id: 20251030-k1-ethernet-fix-autoneg-ae2a92b3c2db Best regards, -- Vivian "dramforever" Wang