diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 8d0fd920289bc..5239b2f045dc1 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -154,11 +154,6 @@ enum { struct mv3310_mactype { bool valid; bool fixed_interface; - /* PHY copper autoneg supports multiple speeds (1G/2.5G/5G/10G) even - * though the host-side interface is fixed (rate matching). This allows - * phylink to validate and advertise all copper speeds. - */ - bool copper_multispeed; phy_interface_t interface_10g; }; @@ -203,6 +198,7 @@ int mv3310_ptp_get_sset_count(struct mv3310_ptp_priv *priv); void mv3310_ptp_get_strings(u8 *data); void mv3310_ptp_get_stats(struct mv3310_ptp_priv *priv, struct ethtool_stats *stats, u64 *data); +bool mv3310_ptp_is_configured(struct mv3310_ptp_priv *priv); #else static inline struct mv3310_ptp_priv * mv3310_ptp_probe(struct phy_device *phydev) @@ -236,6 +232,10 @@ static inline void mv3310_ptp_get_stats(struct mv3310_ptp_priv *priv, struct ethtool_stats *stats, u64 *data) { } +static inline bool mv3310_ptp_is_configured(struct mv3310_ptp_priv *priv) +{ + return false; +} #endif /* Get statistics from the PHY using ethtool */ @@ -386,12 +386,16 @@ static int mv3310_check_firmware(struct phy_device *phydev); static int mv3310_power_up(struct phy_device *phydev) { struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev); + bool ptp_was_configured; int ret; ret = mv3310_check_firmware(phydev); if (ret < 0) return ret; + /* Capture PTP configured state before power_up potentially sets it. */ + ptp_was_configured = mv3310_ptp_is_configured(priv->ptp_priv); + ret = mv3310_ptp_power_up(priv->ptp_priv); if (ret < 0) return ret; @@ -410,15 +414,20 @@ static int mv3310_power_up(struct phy_device *phydev) priv->firmware_ver < 0x00030000) return ret; - /* Poll until SWRST reads 0 (PHY ready for a new reset) before issuing - * SWRST. Without this, the second and subsequent link-up sequences - * result in broken TX/RX. The datasheet specifies bit 15 = 1 means - * reset in progress, 0 means normal operation. - */ - if (phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, - ret, !(ret & MV_V2_33X0_PORT_CTRL_SWRST), - 5000, 200000, true)) - phydev_warn(phydev, "SWRST timed out 200ms\n"); + if (ptp_was_configured) { + /* Skip SWRST if the M-unit was already configured on prior power cycles. + * SWRST (bit 15) resets the entire port and clears M_UNIT_PWRUP, + * forcing WMC auto-negotiation to restart. A MAC SerDes transition + * between ptp_start calls can stall WMC AN, causing the M-unit to + * silently drop all frames. Once the M-unit is configured it must not + * be disturbed. Reproducibility is dependent on timing: + * - with no delay it is ~1/5 + * - with 10ms delay it is ~1/50 + * - with 100ms delay it is ~1/150 + * - with current solution it doesn't reproduce + */ + return ret; + } ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, MV_V2_33X0_PORT_CTRL_SWRST); @@ -962,7 +971,6 @@ static const struct mv3310_mactype mv3310_mactypes[] = { [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { .valid = true, .fixed_interface = true, - .copper_multispeed = true, .interface_10g = PHY_INTERFACE_MODE_10GBASER, }, [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = { @@ -997,7 +1005,6 @@ static const struct mv3310_mactype mv3340_mactypes[] = { [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = { .valid = true, .fixed_interface = true, - .copper_multispeed = true, .interface_10g = PHY_INTERFACE_MODE_10GBASER, }, [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = { @@ -1016,7 +1023,7 @@ static void mv3310_fill_possible_interfaces(struct phy_device *phydev) if (mactype->interface_10g != PHY_INTERFACE_MODE_NA) __set_bit(priv->mactype->interface_10g, possible); - if (!mactype->fixed_interface || mactype->copper_multispeed) { + if (!mactype->fixed_interface) { __set_bit(PHY_INTERFACE_MODE_5GBASER, possible); __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible); __set_bit(PHY_INTERFACE_MODE_SGMII, possible); @@ -1054,15 +1061,10 @@ static int mv3310_config_init(struct phy_device *phydev) mv3310_config_init_clear_power_down(phydev); - /* Force XFI/SGMII/Auto-neg mode regardless of strap configuration. - /* Default to rate-match mode so the host serdes stays fixed at 10GBASE-R - * regardless of copper wire speed. This is correct for MACs (e.g. mvpp2) that - * configure their comphy for 10GBASE-R and cannot handle the PHY switching - * the host interface to SGMII on 1G link-up. - */ + /* Force XFI/SGMII/Auto-neg mode regardless of strap configuration */ err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL, MV_V2_33X0_PORT_CTRL_MACTYPE_MASK, - MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH); + MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER); if (err) return err; diff --git a/drivers/net/phy/marvell10g_ptp.c b/drivers/net/phy/marvell10g_ptp.c index 02496f847b381..1436c06985d9c 100644 --- a/drivers/net/phy/marvell10g_ptp.c +++ b/drivers/net/phy/marvell10g_ptp.c @@ -105,6 +105,12 @@ struct mv3310_ptp_priv { struct mii_timestamper mii_ts; int old_speed; /* Last speed used to set MRU */ bool extts_enabled; + /* True once ptp_power_up has completed successfully. While set, + * ptp_power_up is a no-op (M-unit stays running) and mv3310_power_up + * skips SWRST (which would clear M_UNIT_PWRUP and force WMC AN to + * restart, causing the 1/150 silent frame-drop race). + */ + bool configured; }; struct mv3310_ptp_counter { @@ -142,6 +148,8 @@ int mv3310_ptp_power_up(struct mv3310_ptp_priv *priv); int mv3310_ptp_power_down(struct mv3310_ptp_priv *priv); int mv3310_ptp_start(struct mv3310_ptp_priv *priv); int mv3310_ptp_update(struct mv3310_ptp_priv *priv); +bool mv3310_ptp_is_configured(struct mv3310_ptp_priv *priv); + /* Get statistics from the PHY using ethtool */ int mv3310_ptp_get_sset_count(struct mv3310_ptp_priv *priv); void mv3310_ptp_get_strings(u8 *data); @@ -278,6 +286,11 @@ struct mv3310_ptp_priv *mv3310_ptp_probe(struct phy_device *phydev) return priv; } +bool mv3310_ptp_is_configured(struct mv3310_ptp_priv *priv) +{ + return priv && priv->configured; +} + int mv3310_ptp_power_up(struct mv3310_ptp_priv *priv) { int ret; @@ -307,15 +320,15 @@ int mv3310_ptp_power_up(struct mv3310_ptp_priv *priv) MV_V2_SLC_CFG_GEN_SMC_ADD_CRC | MV_V2_SLC_CFG_GEN_WMC_STRIP_CRC | MV_V2_SLC_CFG_GEN_SMC_STRIP_CRC); - - /* Increase the MRU for the default mode (XG) */ - ret |= mv3310_set_mac_mru(priv, SPEED_10000); - /* Disable store-and-forward mode for egress drop FIFO. Without this setting there are time error spikes of up to 1200ns when performing 1588TC accuracy measurements. */ ret |= mv3310_clear_ptp_reg_bits(phydev, MV_V2_SLC_CFG_GEN, MV_V2_SLC_CFG_GEN_EGR_SF_EN); + + if (ret == 0) + priv->configured = true; + unlock_out: mutex_unlock(&priv->lock); return ret; @@ -364,6 +377,13 @@ int mv3310_ptp_start(struct mv3310_ptp_priv *priv) if (ret < 0) dev_err(&phydev->mdio.dev, "failed to enable PTP core: %d\n", ret); + + /* MRU is applied after link-up via mv3310_ptp_update(). Reset + * old_speed so the next link-up always triggers a write regardless + * of the previous speed class. + */ + priv->old_speed = SPEED_UNKNOWN; + mutex_unlock(&priv->lock); return ret; @@ -396,6 +416,14 @@ static int mv3310_set_mac_mru(struct mv3310_ptp_priv *priv, int speed) return 0; } + /* Configure MRU size depending on the operational speed. According to + * docs: + * 1G mode and 2.5G mode are sharing same set of configuration. + * XG mode and 1/2.5 G mode have separate configuration register + * but enable only one group during operation. + * Therefore two register group act as one after operation speed is + * determined + */ if (speed < SPEED_5000) { /* Configuration registers for 1/2.5G mode */ ret |= mv3310_set_ptp_reg_bits(