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

ethtool: netlink: add ETHTOOL_MSG_MSE_GET and wire up PHY MSE access

Introduce the userspace entry point for PHY MSE diagnostics via
ethtool netlink. This exposes the core API added previously and
returns both capability information and one or more snapshots.

Userspace sends ETHTOOL_MSG_MSE_GET. The reply carries:
- ETHTOOL_A_MSE_CAPABILITIES: scale limits and timing information
- ETHTOOL_A_MSE_CHANNEL_* nests: one or more snapshots (per-channel
if available, otherwise WORST, otherwise LINK)

Link down returns -ENETDOWN.

Changes:
- YAML: add attribute sets (mse, mse-capabilities, mse-snapshot)
and the mse-get operation
- UAPI (generated): add ETHTOOL_A_MSE_* enums and message IDs,
ETHTOOL_MSG_MSE_GET/REPLY
- ethtool core: add net/ethtool/mse.c implementing the request,
register genl op, and hook into ethnl dispatch
- docs: document MSE_GET in ethtool-netlink.rst

The include/uapi/linux/ethtool_netlink_generated.h is generated
from Documentation/netlink/specs/ethtool.yaml.

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

authored by

Oleksij Rempel and committed by
Jakub Kicinski
e6e93fb0 abcf6eef

+527 -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 ===================
+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);