Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 26 additions & 24 deletions drivers/net/phy/marvell10g.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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] = {
Expand Down Expand Up @@ -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] = {
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand Down
36 changes: 32 additions & 4 deletions drivers/net/phy/marvell10g_ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
Loading