Commit fd93ed77 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by Jakub Kicinski
Browse files

net: phy: dp83td510: add MSE interface support for 10BASE-T1L



Implement get_mse_capability() and get_mse_snapshot() for the DP83TD510E
to expose its Mean Square Error (MSE) register via the new PHY MSE
UAPI.

The DP83TD510E does not document any peak MSE values; it only exposes
a single average MSE register used internally to derive SQI. This
implementation therefore advertises only PHY_MSE_CAP_AVG, along with
LINK and channel-A selectors. Scaling is fixed to 0xFFFF, and the
refresh interval/number of symbols are estimated from 10BASE-T1L
symbol rate (7.5 MBd) and typical diagnostic intervals (~1 ms).

For 10BASE-T1L deployments, SQI is a reliable indicator of link
modulation quality once the link is established, but it does not
indicate whether autonegotiation pulses will be correctly received
in marginal conditions. MSE provides a direct measurement of slicer
error rate that can be used to evaluate if autonegotiation is likely
to succeed under a given cable length and condition. In practice,
testing such scenarios often requires forcing a fixed-link setup to
isolate MSE behaviour from the autonegotiation process.

Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: default avatarMaxime Chevallier <maxime.chevallier@bootlin.com>
Link: https://patch.msgid.link/20251027122801.982364-5-o.rempel@pengutronix.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 335a9660
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@
#define DP83TD510E_MASTER_SLAVE_RESOL_FAIL	BIT(15)

#define DP83TD510E_MSE_DETECT			0xa85
#define DP83TD510E_MSE_MAX			U16_MAX

#define DP83TD510_SQI_MAX	7

@@ -249,6 +250,64 @@ struct dp83td510_priv {
#define DP83TD510E_ALCD_COMPLETE			BIT(15)
#define DP83TD510E_ALCD_CABLE_LENGTH			GENMASK(10, 0)

static int dp83td510_get_mse_capability(struct phy_device *phydev,
					struct phy_mse_capability *cap)
{
	/* DP83TD510E documents only a single (average) MSE register
	 * (used to derive SQI); no peak or worst-peak counters are
	 * described. Advertise only PHY_MSE_CAP_AVG.
	 */
	cap->supported_caps = PHY_MSE_CAP_AVG;
	/* 10BASE-T1L is a single-pair medium, so there are no B/C/D channels.
	 * We still advertise PHY_MSE_CAP_CHANNEL_A to indicate that the PHY
	 * can attribute the measurement to a specific pair (the only one),
	 * rather than exposing it only as a link-aggregate.
	 *
	 * Rationale:
	 *  - Keeps the ethtool MSE_GET selection logic consistent: per-channel
	 *    (A/B/C/D) is preferred over WORST/LINK, so userspace receives a
	 *    CHANNEL_A nest instead of LINK.
	 *  - Signals to tools that "per-pair" data is available (even if there's
	 *    just one pair), avoiding the impression that only aggregate values
	 *    are supported.
	 *  - Remains compatible with multi-pair PHYs and uniform UI handling.
	 *
	 * Note: WORST and other channels are not advertised on 10BASE-T1L.
	 */
	cap->supported_caps |= PHY_MSE_CHANNEL_A | PHY_MSE_CAP_LINK;
	cap->max_average_mse = DP83TD510E_MSE_MAX;

	/* The datasheet does not specify the refresh rate or symbol count,
	 * but based on similar PHYs and standards, we can assume a common
	 * value. For 10BASE-T1L, the symbol rate is 7.5 MBd. A common
	 * diagnostic interval is around 1ms.
	 * 7.5e6 symbols/sec * 0.001 sec = 7500 symbols.
	 */
	cap->refresh_rate_ps = 1000000000; /* 1 ms */
	cap->num_symbols = 7500;

	return 0;
}

static int dp83td510_get_mse_snapshot(struct phy_device *phydev,
				      enum phy_mse_channel channel,
				      struct phy_mse_snapshot *snapshot)
{
	int ret;

	if (channel != PHY_MSE_CHANNEL_LINK &&
	    channel != PHY_MSE_CHANNEL_A)
		return -EOPNOTSUPP;

	ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_MSE_DETECT);
	if (ret < 0)
		return ret;

	snapshot->average_mse = ret;

	return 0;
}

static int dp83td510_led_brightness_set(struct phy_device *phydev, u8 index,
					enum led_brightness brightness)
{
@@ -893,6 +952,9 @@ static struct phy_driver dp83td510_driver[] = {
	.get_phy_stats	= dp83td510_get_phy_stats,
	.update_stats	= dp83td510_update_stats,

	.get_mse_capability = dp83td510_get_mse_capability,
	.get_mse_snapshot = dp83td510_get_mse_snapshot,

	.led_brightness_set = dp83td510_led_brightness_set,
	.led_hw_is_supported = dp83td510_led_hw_is_supported,
	.led_hw_control_set = dp83td510_led_hw_control_set,