]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: phy: dp83td510: add MSE interface support for 10BASE-T1L
authorOleksij Rempel <o.rempel@pengutronix.de>
Mon, 27 Oct 2025 12:28:01 +0000 (13:28 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 4 Nov 2025 02:32:27 +0000 (18:32 -0800)
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: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Link: https://patch.msgid.link/20251027122801.982364-5-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/dp83td510.c

index 23af1ac194fa9c0957ade37a7eb7a388534023cd..d75dae6071ad65aab1372f31239428abda17ebfa 100644 (file)
@@ -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,