Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'ethtool-introduce-phy-mse-diagnostics-uapi-and-drivers'

Oleksij Rempel says:

====================
ethtool: introduce PHY MSE diagnostics UAPI and drivers

This series introduces a generic kernel-userspace API for retrieving PHY
Mean Square Error (MSE) diagnostics, together with netlink integration,
a fast-path reporting hook in LINKSTATE_GET, and initial driver
implementations for the KSZ9477 and DP83TD510E PHYs.

MSE is defined by the OPEN Alliance "Advanced diagnostic features for
100BASE-T1 automotive Ethernet PHYs" specification [1] as a measure of
slicer error rate, typically used internally to derive the Signal
Quality Indicator (SQI). While SQI is useful as a normalized quality
index, it hides raw measurement data, varies in scaling and thresholds
between vendors, and may not indicate certain failure modes - for
example, cases where autonegotiation would fail even though SQI reports
a good link. In practice, such scenarios can only be investigated in
fixed-link mode; here, MSE can provide an empirically estimated value
indicating conditions under which autonegotiation would not succeed.

Example output with current implementation:
root@DistroKit:~ ethtool lan1
Settings for lan1:
...
Speed: 1000Mb/s
Duplex: Full
...
Link detected: yes
SQI: 5/7
MSE: 3/127 (channel: worst)

root@DistroKit:~ ethtool --show-mse lan1
MSE diagnostics for lan1:
MSE Configuration:
Max Average MSE: 127
Refresh Rate: 2000000 ps
Symbols per Sample: 250
Supported capabilities: average channel-a channel-b channel-c
channel-d worst

MSE Snapshot (Channel: a):
Average MSE: 4

MSE Snapshot (Channel: b):
Average MSE: 3

MSE Snapshot (Channel: c):
Average MSE: 2

MSE Snapshot (Channel: d):
Average MSE: 3

[1] https://opensig.org/wp-content/uploads/2024/01/Advanced_PHY_features_for_automotive_Ethernet_V1.0.pdf
====================

Link: https://patch.msgid.link/20251027122801.982364-1-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+897 -1
+86
Documentation/netlink/specs/ethtool.yaml
··· 1823 1823 type: uint 1824 1824 enum: pse-event 1825 1825 doc: List of events reported by the PSE controller 1826 + - 1827 + name: mse-capabilities 1828 + doc: MSE capabilities attribute set 1829 + attr-cnt-name: --ethtool-a-mse-capabilities-cnt 1830 + attributes: 1831 + - 1832 + name: max-average-mse 1833 + type: uint 1834 + - 1835 + name: max-peak-mse 1836 + type: uint 1837 + - 1838 + name: refresh-rate-ps 1839 + type: uint 1840 + - 1841 + name: num-symbols 1842 + type: uint 1843 + - 1844 + name: mse-snapshot 1845 + doc: MSE snapshot attribute set 1846 + attr-cnt-name: --ethtool-a-mse-snapshot-cnt 1847 + attributes: 1848 + - 1849 + name: average-mse 1850 + type: uint 1851 + - 1852 + name: peak-mse 1853 + type: uint 1854 + - 1855 + name: worst-peak-mse 1856 + type: uint 1857 + - 1858 + name: mse 1859 + attr-cnt-name: --ethtool-a-mse-cnt 1860 + attributes: 1861 + - 1862 + name: header 1863 + type: nest 1864 + nested-attributes: header 1865 + - 1866 + name: capabilities 1867 + type: nest 1868 + nested-attributes: mse-capabilities 1869 + - 1870 + name: channel-a 1871 + type: nest 1872 + nested-attributes: mse-snapshot 1873 + - 1874 + name: channel-b 1875 + type: nest 1876 + nested-attributes: mse-snapshot 1877 + - 1878 + name: channel-c 1879 + type: nest 1880 + nested-attributes: mse-snapshot 1881 + - 1882 + name: channel-d 1883 + type: nest 1884 + nested-attributes: mse-snapshot 1885 + - 1886 + name: worst-channel 1887 + type: nest 1888 + nested-attributes: mse-snapshot 1889 + - 1890 + name: link 1891 + type: nest 1892 + nested-attributes: mse-snapshot 1826 1893 1827 1894 operations: 1828 1895 enum-model: directional ··· 2823 2756 attributes: 2824 2757 - header 2825 2758 - context 2759 + - 2760 + name: mse-get 2761 + doc: Get PHY MSE measurement data and capabilities. 2762 + attribute-set: mse 2763 + do: &mse-get-op 2764 + request: 2765 + attributes: 2766 + - header 2767 + reply: 2768 + attributes: 2769 + - header 2770 + - capabilities 2771 + - channel-a 2772 + - channel-b 2773 + - channel-c 2774 + - channel-d 2775 + - worst-channel 2776 + - link 2777 + dump: *mse-get-op 2826 2778 2827 2779 mcast-groups: 2828 2780 list:
+64
Documentation/networking/ethtool-netlink.rst
··· 242 242 ``ETHTOOL_MSG_RSS_SET`` set RSS settings 243 243 ``ETHTOOL_MSG_RSS_CREATE_ACT`` create an additional RSS context 244 244 ``ETHTOOL_MSG_RSS_DELETE_ACT`` delete an additional RSS context 245 + ``ETHTOOL_MSG_MSE_GET`` get MSE diagnostic data 245 246 ===================================== ================================= 246 247 247 248 Kernel to userspace: ··· 300 299 ``ETHTOOL_MSG_RSS_CREATE_ACT_REPLY`` create an additional RSS context 301 300 ``ETHTOOL_MSG_RSS_CREATE_NTF`` additional RSS context created 302 301 ``ETHTOOL_MSG_RSS_DELETE_NTF`` additional RSS context deleted 302 + ``ETHTOOL_MSG_MSE_GET_REPLY`` MSE diagnostic data 303 303 ======================================== ================================= 304 304 305 305 ``GET`` requests are sent by userspace applications to retrieve device ··· 2459 2457 ======================================== ====== ============================ 2460 2458 2461 2459 For a description of each attribute, see ``TSCONFIG_GET``. 2460 + 2461 + MSE_GET 2462 + ======= 2463 + 2464 + Retrieves detailed Mean Square Error (MSE) diagnostic information from the PHY. 2465 + 2466 + Request Contents: 2467 + 2468 + ==================================== ====== ============================ 2469 + ``ETHTOOL_A_MSE_HEADER`` nested request header 2470 + ==================================== ====== ============================ 2471 + 2472 + Kernel Response Contents: 2473 + 2474 + ==================================== ====== ================================ 2475 + ``ETHTOOL_A_MSE_HEADER`` nested reply header 2476 + ``ETHTOOL_A_MSE_CAPABILITIES`` nested capability/scale info for MSE 2477 + measurements 2478 + ``ETHTOOL_A_MSE_CHANNEL_A`` nested snapshot for Channel A 2479 + ``ETHTOOL_A_MSE_CHANNEL_B`` nested snapshot for Channel B 2480 + ``ETHTOOL_A_MSE_CHANNEL_C`` nested snapshot for Channel C 2481 + ``ETHTOOL_A_MSE_CHANNEL_D`` nested snapshot for Channel D 2482 + ``ETHTOOL_A_MSE_WORST_CHANNEL`` nested snapshot for worst channel 2483 + ``ETHTOOL_A_MSE_LINK`` nested snapshot for link-wide aggregate 2484 + ==================================== ====== ================================ 2485 + 2486 + MSE Capabilities 2487 + ---------------- 2488 + 2489 + This nested attribute reports the capability / scaling properties used to 2490 + interpret snapshot values. 2491 + 2492 + ============================================== ====== ========================= 2493 + ``ETHTOOL_A_MSE_CAPABILITIES_MAX_AVERAGE_MSE`` uint max avg_mse scale 2494 + ``ETHTOOL_A_MSE_CAPABILITIES_MAX_PEAK_MSE`` uint max peak_mse scale 2495 + ``ETHTOOL_A_MSE_CAPABILITIES_REFRESH_RATE_PS`` uint sample rate (picoseconds) 2496 + ``ETHTOOL_A_MSE_CAPABILITIES_NUM_SYMBOLS`` uint symbols per HW sample 2497 + ============================================== ====== ========================= 2498 + 2499 + The max-average/peak fields are included only if the corresponding metric 2500 + is supported by the PHY. Their absence indicates that the metric is not 2501 + available. 2502 + 2503 + See ``struct phy_mse_capability`` kernel documentation in 2504 + ``include/linux/phy.h``. 2505 + 2506 + MSE Snapshot 2507 + ------------ 2508 + 2509 + Each per-channel nest contains an atomic snapshot of MSE values for that 2510 + selector (channel A/B/C/D, worst channel, or link). 2511 + 2512 + ========================================== ====== =================== 2513 + ``ETHTOOL_A_MSE_SNAPSHOT_AVERAGE_MSE`` uint average MSE value 2514 + ``ETHTOOL_A_MSE_SNAPSHOT_PEAK_MSE`` uint current peak MSE 2515 + ``ETHTOOL_A_MSE_SNAPSHOT_WORST_PEAK_MSE`` uint worst-case peak MSE 2516 + ========================================== ====== =================== 2517 + 2518 + Within each channel nest, only the metrics supported by the PHY will be present. 2519 + 2520 + See ``struct phy_mse_snapshot`` kernel documentation in 2521 + ``include/linux/phy.h``. 2462 2522 2463 2523 Request translation 2464 2524 ===================
+62
drivers/net/phy/dp83td510.c
··· 61 61 #define DP83TD510E_MASTER_SLAVE_RESOL_FAIL BIT(15) 62 62 63 63 #define DP83TD510E_MSE_DETECT 0xa85 64 + #define DP83TD510E_MSE_MAX U16_MAX 64 65 65 66 #define DP83TD510_SQI_MAX 7 66 67 ··· 249 248 #define DP83TD510E_ALCD_STAT 0xa9f 250 249 #define DP83TD510E_ALCD_COMPLETE BIT(15) 251 250 #define DP83TD510E_ALCD_CABLE_LENGTH GENMASK(10, 0) 251 + 252 + static int dp83td510_get_mse_capability(struct phy_device *phydev, 253 + struct phy_mse_capability *cap) 254 + { 255 + /* DP83TD510E documents only a single (average) MSE register 256 + * (used to derive SQI); no peak or worst-peak counters are 257 + * described. Advertise only PHY_MSE_CAP_AVG. 258 + */ 259 + cap->supported_caps = PHY_MSE_CAP_AVG; 260 + /* 10BASE-T1L is a single-pair medium, so there are no B/C/D channels. 261 + * We still advertise PHY_MSE_CAP_CHANNEL_A to indicate that the PHY 262 + * can attribute the measurement to a specific pair (the only one), 263 + * rather than exposing it only as a link-aggregate. 264 + * 265 + * Rationale: 266 + * - Keeps the ethtool MSE_GET selection logic consistent: per-channel 267 + * (A/B/C/D) is preferred over WORST/LINK, so userspace receives a 268 + * CHANNEL_A nest instead of LINK. 269 + * - Signals to tools that "per-pair" data is available (even if there's 270 + * just one pair), avoiding the impression that only aggregate values 271 + * are supported. 272 + * - Remains compatible with multi-pair PHYs and uniform UI handling. 273 + * 274 + * Note: WORST and other channels are not advertised on 10BASE-T1L. 275 + */ 276 + cap->supported_caps |= PHY_MSE_CHANNEL_A | PHY_MSE_CAP_LINK; 277 + cap->max_average_mse = DP83TD510E_MSE_MAX; 278 + 279 + /* The datasheet does not specify the refresh rate or symbol count, 280 + * but based on similar PHYs and standards, we can assume a common 281 + * value. For 10BASE-T1L, the symbol rate is 7.5 MBd. A common 282 + * diagnostic interval is around 1ms. 283 + * 7.5e6 symbols/sec * 0.001 sec = 7500 symbols. 284 + */ 285 + cap->refresh_rate_ps = 1000000000; /* 1 ms */ 286 + cap->num_symbols = 7500; 287 + 288 + return 0; 289 + } 290 + 291 + static int dp83td510_get_mse_snapshot(struct phy_device *phydev, 292 + enum phy_mse_channel channel, 293 + struct phy_mse_snapshot *snapshot) 294 + { 295 + int ret; 296 + 297 + if (channel != PHY_MSE_CHANNEL_LINK && 298 + channel != PHY_MSE_CHANNEL_A) 299 + return -EOPNOTSUPP; 300 + 301 + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_MSE_DETECT); 302 + if (ret < 0) 303 + return ret; 304 + 305 + snapshot->average_mse = ret; 306 + 307 + return 0; 308 + } 252 309 253 310 static int dp83td510_led_brightness_set(struct phy_device *phydev, u8 index, 254 311 enum led_brightness brightness) ··· 951 892 .cable_test_get_status = dp83td510_cable_test_get_status, 952 893 .get_phy_stats = dp83td510_get_phy_stats, 953 894 .update_stats = dp83td510_update_stats, 895 + 896 + .get_mse_capability = dp83td510_get_mse_capability, 897 + .get_mse_snapshot = dp83td510_get_mse_snapshot, 954 898 955 899 .led_brightness_set = dp83td510_led_brightness_set, 956 900 .led_hw_is_supported = dp83td510_led_hw_is_supported,
+102
drivers/net/phy/micrel.c
··· 2325 2325 return KSZ9477_SQI_MAX; 2326 2326 } 2327 2327 2328 + static int kszphy_get_mse_capability(struct phy_device *phydev, 2329 + struct phy_mse_capability *cap) 2330 + { 2331 + /* Capabilities depend on link mode: 2332 + * - 1000BASE-T: per-pair SQI registers exist => expose A..D 2333 + * and a WORST selector. 2334 + * - 100BASE-TX: HW provides a single MSE/SQI reading in the "channel A" 2335 + * register, but with auto MDI-X there is no MDI-X resolution bit, 2336 + * so we cannot map that register to a specific wire pair reliably. 2337 + * To avoid misleading per-channel data, advertise only LINK. 2338 + * Other speeds: no MSE exposure via this driver. 2339 + * 2340 + * Note: WORST is *not* a hardware selector on this family. 2341 + * We expose it because the driver computes it in software 2342 + * by scanning per-channel readouts (A..D) and picking the 2343 + * maximum average MSE. 2344 + */ 2345 + if (phydev->speed == SPEED_1000) 2346 + cap->supported_caps = PHY_MSE_CAP_CHANNEL_A | 2347 + PHY_MSE_CAP_CHANNEL_B | 2348 + PHY_MSE_CAP_CHANNEL_C | 2349 + PHY_MSE_CAP_CHANNEL_D | 2350 + PHY_MSE_CAP_WORST_CHANNEL; 2351 + else if (phydev->speed == SPEED_100) 2352 + cap->supported_caps = PHY_MSE_CAP_LINK; 2353 + else 2354 + return -EOPNOTSUPP; 2355 + 2356 + cap->max_average_mse = FIELD_MAX(KSZ9477_MMD_SQI_MASK); 2357 + cap->refresh_rate_ps = 2000000; /* 2 us */ 2358 + /* Estimated from link modulation (125 MBd per channel) and documented 2359 + * refresh rate of 2 us 2360 + */ 2361 + cap->num_symbols = 250; 2362 + 2363 + cap->supported_caps |= PHY_MSE_CAP_AVG; 2364 + 2365 + return 0; 2366 + } 2367 + 2368 + static int kszphy_get_mse_snapshot(struct phy_device *phydev, 2369 + enum phy_mse_channel channel, 2370 + struct phy_mse_snapshot *snapshot) 2371 + { 2372 + u8 num_channels; 2373 + int ret; 2374 + 2375 + if (phydev->speed == SPEED_1000) 2376 + num_channels = 4; 2377 + else if (phydev->speed == SPEED_100) 2378 + num_channels = 1; 2379 + else 2380 + return -EOPNOTSUPP; 2381 + 2382 + if (channel == PHY_MSE_CHANNEL_WORST) { 2383 + u32 worst_val = 0; 2384 + int i; 2385 + 2386 + /* WORST is implemented in software: select the maximum 2387 + * average MSE across the available per-channel registers. 2388 + * Only defined when multiple channels exist (1000BASE-T). 2389 + */ 2390 + if (num_channels < 2) 2391 + return -EOPNOTSUPP; 2392 + 2393 + for (i = 0; i < num_channels; i++) { 2394 + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 2395 + KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A + i); 2396 + if (ret < 0) 2397 + return ret; 2398 + 2399 + ret = FIELD_GET(KSZ9477_MMD_SQI_MASK, ret); 2400 + if (ret > worst_val) 2401 + worst_val = ret; 2402 + } 2403 + snapshot->average_mse = worst_val; 2404 + } else if (channel == PHY_MSE_CHANNEL_LINK && num_channels == 1) { 2405 + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 2406 + KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A); 2407 + if (ret < 0) 2408 + return ret; 2409 + snapshot->average_mse = FIELD_GET(KSZ9477_MMD_SQI_MASK, ret); 2410 + } else if (channel >= PHY_MSE_CHANNEL_A && 2411 + channel <= PHY_MSE_CHANNEL_D) { 2412 + /* Per-channel readouts are valid only for 1000BASE-T. */ 2413 + if (phydev->speed != SPEED_1000) 2414 + return -EOPNOTSUPP; 2415 + 2416 + ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 2417 + KSZ9477_MMD_SIGNAL_QUALITY_CHAN_A + channel); 2418 + if (ret < 0) 2419 + return ret; 2420 + snapshot->average_mse = FIELD_GET(KSZ9477_MMD_SQI_MASK, ret); 2421 + } else { 2422 + return -EOPNOTSUPP; 2423 + } 2424 + 2425 + return 0; 2426 + } 2427 + 2328 2428 static void kszphy_enable_clk(struct phy_device *phydev) 2329 2429 { 2330 2430 struct kszphy_priv *priv = phydev->priv; ··· 6597 6497 .cable_test_get_status = ksz9x31_cable_test_get_status, 6598 6498 .get_sqi = kszphy_get_sqi, 6599 6499 .get_sqi_max = kszphy_get_sqi_max, 6500 + .get_mse_capability = kszphy_get_mse_capability, 6501 + .get_mse_snapshot = kszphy_get_mse_snapshot, 6600 6502 } }; 6601 6503 6602 6504 module_phy_driver(ksphy_driver);
+206
include/linux/phy.h
··· 903 903 904 904 #define to_phy_led(d) container_of(d, struct phy_led, led_cdev) 905 905 906 + /* 907 + * PHY_MSE_CAP_* - Bitmask flags for Mean Square Error (MSE) capabilities 908 + * 909 + * These flags describe which MSE metrics and selectors are implemented 910 + * by the PHY for the current link mode. They are used in 911 + * struct phy_mse_capability.supported_caps. 912 + * 913 + * Standardization: 914 + * The OPEN Alliance (OA) defines the presence of MSE/SQI/pMSE but not their 915 + * numeric scaling, update intervals, or aggregation windows. See: 916 + * OA 100BASE-T1 TC1 v1.0, sections 6.1.1-6.1.3 917 + * OA 1000BASE-T1 TC12 v2.2, sections 6.1.1-6.1.2 918 + * 919 + * Description of flags: 920 + * 921 + * PHY_MSE_CAP_CHANNEL_A 922 + * Per-pair diagnostics for Channel A are supported. Mapping to the 923 + * physical wire pair may depend on MDI/MDI-X polarity. 924 + * 925 + * PHY_MSE_CAP_CHANNEL_B, _C, _D 926 + * Same as above for channels B-D. 927 + * 928 + * PHY_MSE_CAP_WORST_CHANNEL 929 + * The PHY or driver can identify and report the single worst-performing 930 + * channel without querying each one individually. 931 + * 932 + * PHY_MSE_CAP_LINK 933 + * The PHY provides only a link-wide aggregate measurement or cannot map 934 + * results to a specific pair (for example 100BASE-TX with unknown 935 + * MDI/MDI-X). 936 + * 937 + * PHY_MSE_CAP_AVG 938 + * Average MSE (mean DCQ metric) is supported. For 100/1000BASE-T1 the OA 939 + * recommends 2^16 symbols, scaled 0..511, but the exact scaling is 940 + * vendor-specific. 941 + * 942 + * PHY_MSE_CAP_PEAK 943 + * Peak MSE (current peak within the measurement window) is supported. 944 + * Defined as pMSE for 100BASE-T1; vendor-specific for others. 945 + * 946 + * PHY_MSE_CAP_WORST_PEAK 947 + * Latched worst-case peak MSE since the last read (read-to-clear if 948 + * implemented). Optional in OA 100BASE-T1 TC1 6.1.3. 949 + */ 950 + #define PHY_MSE_CAP_CHANNEL_A BIT(0) 951 + #define PHY_MSE_CAP_CHANNEL_B BIT(1) 952 + #define PHY_MSE_CAP_CHANNEL_C BIT(2) 953 + #define PHY_MSE_CAP_CHANNEL_D BIT(3) 954 + #define PHY_MSE_CAP_WORST_CHANNEL BIT(4) 955 + #define PHY_MSE_CAP_LINK BIT(5) 956 + #define PHY_MSE_CAP_AVG BIT(6) 957 + #define PHY_MSE_CAP_PEAK BIT(7) 958 + #define PHY_MSE_CAP_WORST_PEAK BIT(8) 959 + 960 + /* 961 + * enum phy_mse_channel - Identifiers for selecting MSE measurement channels 962 + * 963 + * PHY_MSE_CHANNEL_A - PHY_MSE_CHANNEL_D 964 + * Select per-pair measurement for the corresponding channel. 965 + * 966 + * PHY_MSE_CHANNEL_WORST 967 + * Select the single worst-performing channel reported by hardware. 968 + * 969 + * PHY_MSE_CHANNEL_LINK 970 + * Select link-wide aggregate data (used when per-pair results are 971 + * unavailable). 972 + */ 973 + enum phy_mse_channel { 974 + PHY_MSE_CHANNEL_A, 975 + PHY_MSE_CHANNEL_B, 976 + PHY_MSE_CHANNEL_C, 977 + PHY_MSE_CHANNEL_D, 978 + PHY_MSE_CHANNEL_WORST, 979 + PHY_MSE_CHANNEL_LINK, 980 + }; 981 + 982 + /** 983 + * struct phy_mse_capability - Capabilities of Mean Square Error (MSE) 984 + * measurement interface 985 + * 986 + * Standardization notes: 987 + * 988 + * - Presence of MSE/SQI/pMSE is defined by OPEN Alliance specs, but numeric 989 + * scaling, refresh/update rate and aggregation windows are not fixed and 990 + * are vendor-/product-specific. (OA 100BASE-T1 TC1 v1.0 6.1.*; 991 + * OA 1000BASE-T1 TC12 v2.2 6.1.*) 992 + * 993 + * - Typical recommendations: 2^16 symbols and 0..511 scaling for MSE; pMSE only 994 + * defined for 100BASE-T1 (sliding window example), others are vendor 995 + * extensions. Drivers must report actual scale/limits here. 996 + * 997 + * Describes the MSE measurement capabilities for the current link mode. These 998 + * properties are dynamic and may change when link settings are modified. 999 + * Callers should re-query this capability after any link state change to 1000 + * ensure they have the most up-to-date information. 1001 + * 1002 + * Callers should only request measurements for channels and types that are 1003 + * indicated as supported by the @supported_caps bitmask. If @supported_caps 1004 + * is 0, the device provides no MSE diagnostics, and driver operations should 1005 + * typically return -EOPNOTSUPP. 1006 + * 1007 + * Snapshot values for average and peak MSE can be normalized to a 0..1 ratio 1008 + * by dividing the raw snapshot by the corresponding @max_average_mse or 1009 + * @max_peak_mse value. 1010 + * 1011 + * @max_average_mse: The maximum value for an average MSE snapshot. This 1012 + * defines the scale for the measurement. If the PHY_MSE_CAP_AVG capability is 1013 + * supported, this value MUST be greater than 0. (vendor-specific units). 1014 + * @max_peak_mse: The maximum value for a peak MSE snapshot. If either 1015 + * PHY_MSE_CAP_PEAK or PHY_MSE_CAP_WORST_PEAK is supported, this value MUST 1016 + * be greater than 0. (vendor-specific units). 1017 + * @refresh_rate_ps: The typical interval, in picoseconds, between hardware 1018 + * updates of the MSE values. This is an estimate, and callers should not 1019 + * assume synchronous sampling. (vendor-specific units). 1020 + * @num_symbols: The number of symbols aggregated per hardware sample to 1021 + * calculate the MSE. (vendor-specific units). 1022 + * @supported_caps: A bitmask of PHY_MSE_CAP_* values indicating which 1023 + * measurement types (e.g., average, peak) and channels 1024 + * (e.g., per-pair or link-wide) are supported. 1025 + */ 1026 + struct phy_mse_capability { 1027 + u64 max_average_mse; 1028 + u64 max_peak_mse; 1029 + u64 refresh_rate_ps; 1030 + u64 num_symbols; 1031 + u32 supported_caps; 1032 + }; 1033 + 1034 + /** 1035 + * struct phy_mse_snapshot - A snapshot of Mean Square Error (MSE) diagnostics 1036 + * 1037 + * Holds a set of MSE diagnostic values that were all captured from a single 1038 + * measurement window. 1039 + * 1040 + * Values are raw, device-scaled and not normalized. Use struct 1041 + * phy_mse_capability to interpret the scale and sampling window. 1042 + * 1043 + * @average_mse: The average MSE value over the measurement window. 1044 + * OPEN Alliance references MSE as a DCQ metric; recommends 2^16 symbols and 1045 + * 0..511 scaling. Exact scale and refresh are vendor-specific. 1046 + * (100BASE-T1 TC1 v1.0 6.1.1; 1000BASE-T1 TC12 v2.2 6.1.1). 1047 + * 1048 + * @peak_mse: The peak MSE value observed within the measurement window. 1049 + * For 100BASE-T1, "pMSE" is optional and may be implemented via a sliding 1050 + * 128-symbol window with periodic capture; not standardized for 1000BASE-T1. 1051 + * (100BASE-T1 TC1 v1.0 6.1.3, Table "DCQ.peakMSE"). 1052 + * 1053 + * @worst_peak_mse: A latched high-water mark of the peak MSE since last read 1054 + * (read-to-clear if implemented). OPEN Alliance shows a latched "worst case 1055 + * peak MSE" for 100BASE-T1 pMSE; availability/semantics outside that are 1056 + * vendor-specific. (100BASE-T1 TC1 v1.0 6.1.3, DCQ.peakMSE high byte; 1057 + * 1000BASE-T1 TC12 v2.2 treats DCQ details as vendor-specific.) 1058 + */ 1059 + struct phy_mse_snapshot { 1060 + u64 average_mse; 1061 + u64 peak_mse; 1062 + u64 worst_peak_mse; 1063 + }; 1064 + 906 1065 /** 907 1066 * struct phy_driver - Driver structure for a particular PHY type 908 1067 * ··· 1342 1183 int (*get_sqi)(struct phy_device *dev); 1343 1184 /** @get_sqi_max: Get the maximum signal quality indication */ 1344 1185 int (*get_sqi_max)(struct phy_device *dev); 1186 + 1187 + /** 1188 + * @get_mse_capability: Get capabilities and scale of MSE measurement 1189 + * @dev: PHY device 1190 + * @cap: Output (filled on success) 1191 + * 1192 + * Fill @cap with the PHY's MSE capability for the current 1193 + * link mode: scale limits (max_average_mse, max_peak_mse), update 1194 + * interval (refresh_rate_ps), sample length (num_symbols) and the 1195 + * capability bitmask (supported_caps). 1196 + * 1197 + * Implementations may defer capability report until hardware has 1198 + * converged; in that case they should return -EAGAIN and allow the 1199 + * caller to retry later. 1200 + * 1201 + * Return: 0 on success. On failure, returns a negative errno code, such 1202 + * as -EOPNOTSUPP if MSE measurement is not supported by the PHY or in 1203 + * the current link mode, or -EAGAIN if the capability information is 1204 + * not yet available. 1205 + */ 1206 + int (*get_mse_capability)(struct phy_device *dev, 1207 + struct phy_mse_capability *cap); 1208 + 1209 + /** 1210 + * @get_mse_snapshot: Retrieve a snapshot of MSE diagnostic values 1211 + * @dev: PHY device 1212 + * @channel: Channel identifier (PHY_MSE_CHANNEL_*) 1213 + * @snapshot: Output (filled on success) 1214 + * 1215 + * Fill @snapshot with a correlated set of MSE values from the most 1216 + * recent measurement window. 1217 + * 1218 + * Callers must validate @channel against supported_caps returned by 1219 + * get_mse_capability(). Drivers must not coerce @channel; if the 1220 + * requested selector is not implemented by the device or current link 1221 + * mode, the operation must fail. 1222 + * 1223 + * worst_peak_mse is latched and must be treated as read-to-clear. 1224 + * 1225 + * Return: 0 on success. On failure, returns a negative errno code, such 1226 + * as -EOPNOTSUPP if MSE measurement is not supported by the PHY or in 1227 + * the current link mode, or -EAGAIN if measurements are not yet 1228 + * available. 1229 + */ 1230 + int (*get_mse_snapshot)(struct phy_device *dev, 1231 + enum phy_mse_channel channel, 1232 + struct phy_mse_snapshot *snapshot); 1345 1233 1346 1234 /* PLCA RS interface */ 1347 1235 /** @get_plca_cfg: Return the current PLCA configuration */
+1 -1
net/ethtool/Makefile
··· 9 9 channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ 10 10 tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \ 11 11 module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o \ 12 - phy.o tsconfig.o 12 + phy.o tsconfig.o mse.o
+329
net/ethtool/mse.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/ethtool.h> 4 + #include <linux/phy.h> 5 + #include <linux/slab.h> 6 + 7 + #include "netlink.h" 8 + #include "common.h" 9 + 10 + /* Channels A-D only; WORST and LINK are exclusive alternatives */ 11 + #define PHY_MSE_CHANNEL_COUNT 4 12 + 13 + struct mse_req_info { 14 + struct ethnl_req_info base; 15 + }; 16 + 17 + struct mse_snapshot_entry { 18 + struct phy_mse_snapshot snapshot; 19 + int channel; 20 + }; 21 + 22 + struct mse_reply_data { 23 + struct ethnl_reply_data base; 24 + struct phy_mse_capability capability; 25 + struct mse_snapshot_entry *snapshots; 26 + unsigned int num_snapshots; 27 + }; 28 + 29 + static struct mse_reply_data * 30 + mse_repdata(const struct ethnl_reply_data *reply_base) 31 + { 32 + return container_of(reply_base, struct mse_reply_data, base); 33 + } 34 + 35 + const struct nla_policy ethnl_mse_get_policy[] = { 36 + [ETHTOOL_A_MSE_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy_phy), 37 + }; 38 + 39 + static int get_snapshot_if_supported(struct phy_device *phydev, 40 + struct mse_reply_data *data, 41 + unsigned int *idx, u32 cap_bit, 42 + enum phy_mse_channel channel) 43 + { 44 + int ret; 45 + 46 + if (data->capability.supported_caps & cap_bit) { 47 + ret = phydev->drv->get_mse_snapshot(phydev, channel, 48 + &data->snapshots[*idx].snapshot); 49 + if (ret) 50 + return ret; 51 + data->snapshots[*idx].channel = channel; 52 + (*idx)++; 53 + } 54 + 55 + return 0; 56 + } 57 + 58 + static int mse_get_channels(struct phy_device *phydev, 59 + struct mse_reply_data *data) 60 + { 61 + unsigned int i = 0; 62 + int ret; 63 + 64 + if (!data->capability.supported_caps) 65 + return 0; 66 + 67 + data->snapshots = kcalloc(PHY_MSE_CHANNEL_COUNT, 68 + sizeof(*data->snapshots), GFP_KERNEL); 69 + if (!data->snapshots) 70 + return -ENOMEM; 71 + 72 + /* Priority 1: Individual channels */ 73 + ret = get_snapshot_if_supported(phydev, data, &i, PHY_MSE_CAP_CHANNEL_A, 74 + PHY_MSE_CHANNEL_A); 75 + if (ret) 76 + return ret; 77 + ret = get_snapshot_if_supported(phydev, data, &i, PHY_MSE_CAP_CHANNEL_B, 78 + PHY_MSE_CHANNEL_B); 79 + if (ret) 80 + return ret; 81 + ret = get_snapshot_if_supported(phydev, data, &i, PHY_MSE_CAP_CHANNEL_C, 82 + PHY_MSE_CHANNEL_C); 83 + if (ret) 84 + return ret; 85 + ret = get_snapshot_if_supported(phydev, data, &i, PHY_MSE_CAP_CHANNEL_D, 86 + PHY_MSE_CHANNEL_D); 87 + if (ret) 88 + return ret; 89 + 90 + /* If any individual channels were found, we are done. */ 91 + if (i > 0) { 92 + data->num_snapshots = i; 93 + return 0; 94 + } 95 + 96 + /* Priority 2: Worst channel, if no individual channels supported. */ 97 + ret = get_snapshot_if_supported(phydev, data, &i, 98 + PHY_MSE_CAP_WORST_CHANNEL, 99 + PHY_MSE_CHANNEL_WORST); 100 + if (ret) 101 + return ret; 102 + 103 + /* If worst channel was found, we are done. */ 104 + if (i > 0) { 105 + data->num_snapshots = i; 106 + return 0; 107 + } 108 + 109 + /* Priority 3: Link-wide, if nothing else is supported. */ 110 + ret = get_snapshot_if_supported(phydev, data, &i, PHY_MSE_CAP_LINK, 111 + PHY_MSE_CHANNEL_LINK); 112 + if (ret) 113 + return ret; 114 + 115 + data->num_snapshots = i; 116 + return 0; 117 + } 118 + 119 + static int mse_prepare_data(const struct ethnl_req_info *req_base, 120 + struct ethnl_reply_data *reply_base, 121 + const struct genl_info *info) 122 + { 123 + struct mse_reply_data *data = mse_repdata(reply_base); 124 + struct net_device *dev = reply_base->dev; 125 + struct phy_device *phydev; 126 + int ret; 127 + 128 + phydev = ethnl_req_get_phydev(req_base, info->attrs, 129 + ETHTOOL_A_MSE_HEADER, info->extack); 130 + if (IS_ERR(phydev)) 131 + return PTR_ERR(phydev); 132 + if (!phydev) 133 + return -EOPNOTSUPP; 134 + 135 + ret = ethnl_ops_begin(dev); 136 + if (ret) 137 + return ret; 138 + 139 + mutex_lock(&phydev->lock); 140 + 141 + if (!phydev->drv || !phydev->drv->get_mse_capability || 142 + !phydev->drv->get_mse_snapshot) { 143 + ret = -EOPNOTSUPP; 144 + goto out_unlock; 145 + } 146 + if (!phydev->link) { 147 + ret = -ENETDOWN; 148 + goto out_unlock; 149 + } 150 + 151 + ret = phydev->drv->get_mse_capability(phydev, &data->capability); 152 + if (ret) 153 + goto out_unlock; 154 + 155 + ret = mse_get_channels(phydev, data); 156 + 157 + out_unlock: 158 + mutex_unlock(&phydev->lock); 159 + ethnl_ops_complete(dev); 160 + if (ret) 161 + kfree(data->snapshots); 162 + return ret; 163 + } 164 + 165 + static void mse_cleanup_data(struct ethnl_reply_data *reply_base) 166 + { 167 + struct mse_reply_data *data = mse_repdata(reply_base); 168 + 169 + kfree(data->snapshots); 170 + } 171 + 172 + static int mse_reply_size(const struct ethnl_req_info *req_base, 173 + const struct ethnl_reply_data *reply_base) 174 + { 175 + const struct mse_reply_data *data = mse_repdata(reply_base); 176 + size_t len = 0; 177 + unsigned int i; 178 + 179 + /* ETHTOOL_A_MSE_CAPABILITIES */ 180 + len += nla_total_size(0); 181 + if (data->capability.supported_caps & PHY_MSE_CAP_AVG) 182 + /* ETHTOOL_A_MSE_CAPABILITIES_MAX_AVERAGE_MSE */ 183 + len += nla_total_size(sizeof(u64)); 184 + if (data->capability.supported_caps & (PHY_MSE_CAP_PEAK | 185 + PHY_MSE_CAP_WORST_PEAK)) 186 + /* ETHTOOL_A_MSE_CAPABILITIES_MAX_PEAK_MSE */ 187 + len += nla_total_size(sizeof(u64)); 188 + /* ETHTOOL_A_MSE_CAPABILITIES_REFRESH_RATE_PS */ 189 + len += nla_total_size(sizeof(u64)); 190 + /* ETHTOOL_A_MSE_CAPABILITIES_NUM_SYMBOLS */ 191 + len += nla_total_size(sizeof(u64)); 192 + 193 + for (i = 0; i < data->num_snapshots; i++) { 194 + size_t snapshot_len = 0; 195 + 196 + /* Per-channel nest (e.g., ETHTOOL_A_MSE_CHANNEL_A / _B / _C / 197 + * _D / _WORST_CHANNEL / _LINK) 198 + */ 199 + snapshot_len += nla_total_size(0); 200 + 201 + if (data->capability.supported_caps & PHY_MSE_CAP_AVG) 202 + snapshot_len += nla_total_size(sizeof(u64)); 203 + if (data->capability.supported_caps & PHY_MSE_CAP_PEAK) 204 + snapshot_len += nla_total_size(sizeof(u64)); 205 + if (data->capability.supported_caps & PHY_MSE_CAP_WORST_PEAK) 206 + snapshot_len += nla_total_size(sizeof(u64)); 207 + 208 + len += snapshot_len; 209 + } 210 + 211 + return len; 212 + } 213 + 214 + static int mse_channel_to_attr(int ch) 215 + { 216 + switch (ch) { 217 + case PHY_MSE_CHANNEL_A: 218 + return ETHTOOL_A_MSE_CHANNEL_A; 219 + case PHY_MSE_CHANNEL_B: 220 + return ETHTOOL_A_MSE_CHANNEL_B; 221 + case PHY_MSE_CHANNEL_C: 222 + return ETHTOOL_A_MSE_CHANNEL_C; 223 + case PHY_MSE_CHANNEL_D: 224 + return ETHTOOL_A_MSE_CHANNEL_D; 225 + case PHY_MSE_CHANNEL_WORST: 226 + return ETHTOOL_A_MSE_WORST_CHANNEL; 227 + case PHY_MSE_CHANNEL_LINK: 228 + return ETHTOOL_A_MSE_LINK; 229 + default: 230 + return -EINVAL; 231 + } 232 + } 233 + 234 + static int mse_fill_reply(struct sk_buff *skb, 235 + const struct ethnl_req_info *req_base, 236 + const struct ethnl_reply_data *reply_base) 237 + { 238 + const struct mse_reply_data *data = mse_repdata(reply_base); 239 + struct nlattr *nest; 240 + unsigned int i; 241 + int ret; 242 + 243 + nest = nla_nest_start(skb, ETHTOOL_A_MSE_CAPABILITIES); 244 + if (!nest) 245 + return -EMSGSIZE; 246 + 247 + if (data->capability.supported_caps & PHY_MSE_CAP_AVG) { 248 + ret = nla_put_uint(skb, 249 + ETHTOOL_A_MSE_CAPABILITIES_MAX_AVERAGE_MSE, 250 + data->capability.max_average_mse); 251 + if (ret < 0) 252 + goto nla_put_nest_failure; 253 + } 254 + 255 + if (data->capability.supported_caps & (PHY_MSE_CAP_PEAK | 256 + PHY_MSE_CAP_WORST_PEAK)) { 257 + ret = nla_put_uint(skb, ETHTOOL_A_MSE_CAPABILITIES_MAX_PEAK_MSE, 258 + data->capability.max_peak_mse); 259 + if (ret < 0) 260 + goto nla_put_nest_failure; 261 + } 262 + 263 + ret = nla_put_uint(skb, ETHTOOL_A_MSE_CAPABILITIES_REFRESH_RATE_PS, 264 + data->capability.refresh_rate_ps); 265 + if (ret < 0) 266 + goto nla_put_nest_failure; 267 + 268 + ret = nla_put_uint(skb, ETHTOOL_A_MSE_CAPABILITIES_NUM_SYMBOLS, 269 + data->capability.num_symbols); 270 + if (ret < 0) 271 + goto nla_put_nest_failure; 272 + 273 + nla_nest_end(skb, nest); 274 + 275 + for (i = 0; i < data->num_snapshots; i++) { 276 + const struct mse_snapshot_entry *s = &data->snapshots[i]; 277 + int chan_attr; 278 + 279 + chan_attr = mse_channel_to_attr(s->channel); 280 + if (chan_attr < 0) 281 + return chan_attr; 282 + 283 + nest = nla_nest_start(skb, chan_attr); 284 + if (!nest) 285 + return -EMSGSIZE; 286 + 287 + if (data->capability.supported_caps & PHY_MSE_CAP_AVG) { 288 + ret = nla_put_uint(skb, 289 + ETHTOOL_A_MSE_SNAPSHOT_AVERAGE_MSE, 290 + s->snapshot.average_mse); 291 + if (ret) 292 + goto nla_put_nest_failure; 293 + } 294 + if (data->capability.supported_caps & PHY_MSE_CAP_PEAK) { 295 + ret = nla_put_uint(skb, ETHTOOL_A_MSE_SNAPSHOT_PEAK_MSE, 296 + s->snapshot.peak_mse); 297 + if (ret) 298 + goto nla_put_nest_failure; 299 + } 300 + if (data->capability.supported_caps & PHY_MSE_CAP_WORST_PEAK) { 301 + ret = nla_put_uint(skb, 302 + ETHTOOL_A_MSE_SNAPSHOT_WORST_PEAK_MSE, 303 + s->snapshot.worst_peak_mse); 304 + if (ret) 305 + goto nla_put_nest_failure; 306 + } 307 + 308 + nla_nest_end(skb, nest); 309 + } 310 + 311 + return 0; 312 + 313 + nla_put_nest_failure: 314 + nla_nest_cancel(skb, nest); 315 + return ret; 316 + } 317 + 318 + const struct ethnl_request_ops ethnl_mse_request_ops = { 319 + .request_cmd = ETHTOOL_MSG_MSE_GET, 320 + .reply_cmd = ETHTOOL_MSG_MSE_GET_REPLY, 321 + .hdr_attr = ETHTOOL_A_MSE_HEADER, 322 + .req_info_size = sizeof(struct mse_req_info), 323 + .reply_data_size = sizeof(struct mse_reply_data), 324 + 325 + .prepare_data = mse_prepare_data, 326 + .cleanup_data = mse_cleanup_data, 327 + .reply_size = mse_reply_size, 328 + .fill_reply = mse_fill_reply, 329 + };
+10
net/ethtool/netlink.c
··· 420 420 [ETHTOOL_MSG_TSCONFIG_GET] = &ethnl_tsconfig_request_ops, 421 421 [ETHTOOL_MSG_TSCONFIG_SET] = &ethnl_tsconfig_request_ops, 422 422 [ETHTOOL_MSG_PHY_GET] = &ethnl_phy_request_ops, 423 + [ETHTOOL_MSG_MSE_GET] = &ethnl_mse_request_ops, 423 424 }; 424 425 425 426 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) ··· 1534 1533 .doit = ethnl_rss_delete_doit, 1535 1534 .policy = ethnl_rss_delete_policy, 1536 1535 .maxattr = ARRAY_SIZE(ethnl_rss_delete_policy) - 1, 1536 + }, 1537 + { 1538 + .cmd = ETHTOOL_MSG_MSE_GET, 1539 + .doit = ethnl_default_doit, 1540 + .start = ethnl_perphy_start, 1541 + .dumpit = ethnl_perphy_dumpit, 1542 + .done = ethnl_perphy_done, 1543 + .policy = ethnl_mse_get_policy, 1544 + .maxattr = ARRAY_SIZE(ethnl_mse_get_policy) - 1, 1537 1545 }, 1538 1546 }; 1539 1547
+2
net/ethtool/netlink.h
··· 442 442 extern const struct ethnl_request_ops ethnl_mm_request_ops; 443 443 extern const struct ethnl_request_ops ethnl_phy_request_ops; 444 444 extern const struct ethnl_request_ops ethnl_tsconfig_request_ops; 445 + extern const struct ethnl_request_ops ethnl_mse_request_ops; 445 446 446 447 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; 447 448 extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; ··· 498 497 extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1]; 499 498 extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1]; 500 499 extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1]; 500 + extern const struct nla_policy ethnl_mse_get_policy[ETHTOOL_A_MSE_HEADER + 1]; 501 501 502 502 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); 503 503 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);