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

ethtool: provide timestamping information with TSINFO_GET request

Implement TSINFO_GET request to get timestamping information for a network
device. This is traditionally available via ETHTOOL_GET_TS_INFO ioctl
request.

Move part of ethtool_get_ts_info() into common.c so that ioctl and netlink
code use the same logic to get timestamping information from the device.

v3: use "TSINFO" rather than "TIMESTAMP", suggested by Richard Cochran

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michal Kubecek and committed by
David S. Miller
5b071c59 f76510b4

+225 -21
+29 -1
Documentation/networking/ethtool-netlink.rst
··· 203 203 ``ETHTOOL_MSG_PAUSE_SET`` set pause parameters 204 204 ``ETHTOOL_MSG_EEE_GET`` get EEE settings 205 205 ``ETHTOOL_MSG_EEE_SET`` set EEE settings 206 + ``ETHTOOL_MSG_TSINFO_GET`` get timestamping info 206 207 ===================================== ================================ 207 208 208 209 Kernel to userspace: ··· 234 233 ``ETHTOOL_MSG_PAUSE_NTF`` pause parameters 235 234 ``ETHTOOL_MSG_EEE_GET_REPLY`` EEE settings 236 235 ``ETHTOOL_MSG_EEE_NTF`` EEE settings 236 + ``ETHTOOL_MSG_TSINFO_GET_REPLY`` timestamping info 237 237 ===================================== ================================= 238 238 239 239 ``GET`` requests are sent by userspace applications to retrieve device ··· 930 928 callback supports. 931 929 932 930 931 + TSINFO_GET 932 + ========== 933 + 934 + Gets timestamping information like ``ETHTOOL_GET_TS_INFO`` ioctl request. 935 + 936 + Request contents: 937 + 938 + ===================================== ====== ========================== 939 + ``ETHTOOL_A_TSINFO_HEADER`` nested request header 940 + ===================================== ====== ========================== 941 + 942 + Kernel response contents: 943 + 944 + ===================================== ====== ========================== 945 + ``ETHTOOL_A_TSINFO_HEADER`` nested request header 946 + ``ETHTOOL_A_TSINFO_TIMESTAMPING`` bitset SO_TIMESTAMPING flags 947 + ``ETHTOOL_A_TSINFO_TX_TYPES`` bitset supported Tx types 948 + ``ETHTOOL_A_TSINFO_RX_FILTERS`` bitset supported Rx filters 949 + ``ETHTOOL_A_TSINFO_PHC_INDEX`` u32 PTP hw clock index 950 + ===================================== ====== ========================== 951 + 952 + ``ETHTOOL_A_TSINFO_PHC_INDEX`` is absent if there is no associated PHC (there 953 + is no special value for this case). The bitset attributes are omitted if they 954 + would be empty (no bit set). 955 + 956 + 933 957 Request translation 934 958 =================== 935 959 ··· 1031 1003 ``ETHTOOL_SET_DUMP`` n/a 1032 1004 ``ETHTOOL_GET_DUMP_FLAG`` n/a 1033 1005 ``ETHTOOL_GET_DUMP_DATA`` n/a 1034 - ``ETHTOOL_GET_TS_INFO`` n/a 1006 + ``ETHTOOL_GET_TS_INFO`` ``ETHTOOL_MSG_TSINFO_GET`` 1035 1007 ``ETHTOOL_GMODULEINFO`` n/a 1036 1008 ``ETHTOOL_GMODULEEEPROM`` n/a 1037 1009 ``ETHTOOL_GEEE`` ``ETHTOOL_MSG_EEE_GET``
+17
include/uapi/linux/ethtool_netlink.h
··· 38 38 ETHTOOL_MSG_PAUSE_SET, 39 39 ETHTOOL_MSG_EEE_GET, 40 40 ETHTOOL_MSG_EEE_SET, 41 + ETHTOOL_MSG_TSINFO_GET, 41 42 42 43 /* add new constants above here */ 43 44 __ETHTOOL_MSG_USER_CNT, ··· 73 72 ETHTOOL_MSG_PAUSE_NTF, 74 73 ETHTOOL_MSG_EEE_GET_REPLY, 75 74 ETHTOOL_MSG_EEE_NTF, 75 + ETHTOOL_MSG_TSINFO_GET_REPLY, 76 76 77 77 /* add new constants above here */ 78 78 __ETHTOOL_MSG_KERNEL_CNT, ··· 386 384 /* add new constants above here */ 387 385 __ETHTOOL_A_EEE_CNT, 388 386 ETHTOOL_A_EEE_MAX = (__ETHTOOL_A_EEE_CNT - 1) 387 + }; 388 + 389 + /* TSINFO */ 390 + 391 + enum { 392 + ETHTOOL_A_TSINFO_UNSPEC, 393 + ETHTOOL_A_TSINFO_HEADER, /* nest - _A_HEADER_* */ 394 + ETHTOOL_A_TSINFO_TIMESTAMPING, /* bitset */ 395 + ETHTOOL_A_TSINFO_TX_TYPES, /* bitset */ 396 + ETHTOOL_A_TSINFO_RX_FILTERS, /* bitset */ 397 + ETHTOOL_A_TSINFO_PHC_INDEX, /* u32 */ 398 + 399 + /* add new constants above here */ 400 + __ETHTOOL_A_TSINFO_CNT, 401 + ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1) 389 402 }; 390 403 391 404 /* generic netlink info */
+1 -1
net/ethtool/Makefile
··· 6 6 7 7 ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o \ 8 8 linkstate.o debug.o wol.o features.o privflags.o rings.o \ 9 - channels.o coalesce.o pause.o eee.o 9 + channels.o coalesce.o pause.o eee.o tsinfo.o
+21
net/ethtool/common.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 3 3 #include <linux/net_tstamp.h> 4 + #include <linux/phy.h> 4 5 5 6 #include "common.h" 6 7 ··· 349 348 * the fact that ops are checked at registration time does not 350 349 * mean the ops attached to a netdev later on are sane. 351 350 */ 351 + return 0; 352 + } 353 + 354 + int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) 355 + { 356 + const struct ethtool_ops *ops = dev->ethtool_ops; 357 + struct phy_device *phydev = dev->phydev; 358 + 359 + memset(info, 0, sizeof(*info)); 360 + info->cmd = ETHTOOL_GET_TS_INFO; 361 + 362 + if (phy_has_tsinfo(phydev)) 363 + return phy_ts_info(phydev, info); 364 + if (ops->get_ts_info) 365 + return ops->get_ts_info(dev, info); 366 + 367 + info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | 368 + SOF_TIMESTAMPING_SOFTWARE; 369 + info->phc_index = -1; 370 + 352 371 return 0; 353 372 }
+1
net/ethtool/common.h
··· 35 35 struct ethtool_link_ksettings *link_ksettings, 36 36 const struct ethtool_cmd *legacy_settings); 37 37 int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max); 38 + int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); 38 39 39 40 #endif /* _ETHTOOL_COMMON_H */
+4 -19
net/ethtool/ioctl.c
··· 2140 2140 2141 2141 static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr) 2142 2142 { 2143 - int err = 0; 2144 2143 struct ethtool_ts_info info; 2145 - const struct ethtool_ops *ops = dev->ethtool_ops; 2146 - struct phy_device *phydev = dev->phydev; 2144 + int err; 2147 2145 2148 - memset(&info, 0, sizeof(info)); 2149 - info.cmd = ETHTOOL_GET_TS_INFO; 2150 - 2151 - if (phy_has_tsinfo(phydev)) { 2152 - err = phy_ts_info(phydev, &info); 2153 - } else if (ops->get_ts_info) { 2154 - err = ops->get_ts_info(dev, &info); 2155 - } else { 2156 - info.so_timestamping = 2157 - SOF_TIMESTAMPING_RX_SOFTWARE | 2158 - SOF_TIMESTAMPING_SOFTWARE; 2159 - info.phc_index = -1; 2160 - } 2161 - 2146 + err = __ethtool_get_ts_info(dev, &info); 2162 2147 if (err) 2163 2148 return err; 2164 2149 2165 2150 if (copy_to_user(useraddr, &info, sizeof(info))) 2166 - err = -EFAULT; 2151 + return -EFAULT; 2167 2152 2168 - return err; 2153 + return 0; 2169 2154 } 2170 2155 2171 2156 static int __ethtool_get_module_info(struct net_device *dev,
+8
net/ethtool/netlink.c
··· 230 230 [ETHTOOL_MSG_COALESCE_GET] = &ethnl_coalesce_request_ops, 231 231 [ETHTOOL_MSG_PAUSE_GET] = &ethnl_pause_request_ops, 232 232 [ETHTOOL_MSG_EEE_GET] = &ethnl_eee_request_ops, 233 + [ETHTOOL_MSG_TSINFO_GET] = &ethnl_tsinfo_request_ops, 233 234 }; 234 235 235 236 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) ··· 831 830 .cmd = ETHTOOL_MSG_EEE_SET, 832 831 .flags = GENL_UNS_ADMIN_PERM, 833 832 .doit = ethnl_set_eee, 833 + }, 834 + { 835 + .cmd = ETHTOOL_MSG_TSINFO_GET, 836 + .doit = ethnl_default_doit, 837 + .start = ethnl_default_start, 838 + .dumpit = ethnl_default_dumpit, 839 + .done = ethnl_default_done, 834 840 }, 835 841 }; 836 842
+1
net/ethtool/netlink.h
··· 344 344 extern const struct ethnl_request_ops ethnl_coalesce_request_ops; 345 345 extern const struct ethnl_request_ops ethnl_pause_request_ops; 346 346 extern const struct ethnl_request_ops ethnl_eee_request_ops; 347 + extern const struct ethnl_request_ops ethnl_tsinfo_request_ops; 347 348 348 349 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); 349 350 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
+143
net/ethtool/tsinfo.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/net_tstamp.h> 4 + 5 + #include "netlink.h" 6 + #include "common.h" 7 + #include "bitset.h" 8 + 9 + struct tsinfo_req_info { 10 + struct ethnl_req_info base; 11 + }; 12 + 13 + struct tsinfo_reply_data { 14 + struct ethnl_reply_data base; 15 + struct ethtool_ts_info ts_info; 16 + }; 17 + 18 + #define TSINFO_REPDATA(__reply_base) \ 19 + container_of(__reply_base, struct tsinfo_reply_data, base) 20 + 21 + static const struct nla_policy 22 + tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1] = { 23 + [ETHTOOL_A_TSINFO_UNSPEC] = { .type = NLA_REJECT }, 24 + [ETHTOOL_A_TSINFO_HEADER] = { .type = NLA_NESTED }, 25 + [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .type = NLA_REJECT }, 26 + [ETHTOOL_A_TSINFO_TX_TYPES] = { .type = NLA_REJECT }, 27 + [ETHTOOL_A_TSINFO_RX_FILTERS] = { .type = NLA_REJECT }, 28 + [ETHTOOL_A_TSINFO_PHC_INDEX] = { .type = NLA_REJECT }, 29 + }; 30 + 31 + static int tsinfo_prepare_data(const struct ethnl_req_info *req_base, 32 + struct ethnl_reply_data *reply_base, 33 + struct genl_info *info) 34 + { 35 + struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base); 36 + struct net_device *dev = reply_base->dev; 37 + int ret; 38 + 39 + ret = ethnl_ops_begin(dev); 40 + if (ret < 0) 41 + return ret; 42 + ret = __ethtool_get_ts_info(dev, &data->ts_info); 43 + ethnl_ops_complete(dev); 44 + 45 + return ret; 46 + } 47 + 48 + static int tsinfo_reply_size(const struct ethnl_req_info *req_base, 49 + const struct ethnl_reply_data *reply_base) 50 + { 51 + const struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base); 52 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 53 + const struct ethtool_ts_info *ts_info = &data->ts_info; 54 + int len = 0; 55 + int ret; 56 + 57 + BUILD_BUG_ON(__SOF_TIMESTAMPING_CNT > 32); 58 + BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32); 59 + BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32); 60 + 61 + if (ts_info->so_timestamping) { 62 + ret = ethnl_bitset32_size(&ts_info->so_timestamping, NULL, 63 + __SOF_TIMESTAMPING_CNT, 64 + sof_timestamping_names, compact); 65 + if (ret < 0) 66 + return ret; 67 + len += ret; /* _TSINFO_TIMESTAMPING */ 68 + } 69 + if (ts_info->tx_types) { 70 + ret = ethnl_bitset32_size(&ts_info->tx_types, NULL, 71 + __HWTSTAMP_TX_CNT, 72 + ts_tx_type_names, compact); 73 + if (ret < 0) 74 + return ret; 75 + len += ret; /* _TSINFO_TX_TYPES */ 76 + } 77 + if (ts_info->rx_filters) { 78 + ret = ethnl_bitset32_size(&ts_info->rx_filters, NULL, 79 + __HWTSTAMP_FILTER_CNT, 80 + ts_rx_filter_names, compact); 81 + if (ret < 0) 82 + return ret; 83 + len += ret; /* _TSINFO_RX_FILTERS */ 84 + } 85 + if (ts_info->phc_index >= 0) 86 + len += nla_total_size(sizeof(u32)); /* _TSINFO_PHC_INDEX */ 87 + 88 + return len; 89 + } 90 + 91 + static int tsinfo_fill_reply(struct sk_buff *skb, 92 + const struct ethnl_req_info *req_base, 93 + const struct ethnl_reply_data *reply_base) 94 + { 95 + const struct tsinfo_reply_data *data = TSINFO_REPDATA(reply_base); 96 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 97 + const struct ethtool_ts_info *ts_info = &data->ts_info; 98 + int ret; 99 + 100 + if (ts_info->so_timestamping) { 101 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_TIMESTAMPING, 102 + &ts_info->so_timestamping, NULL, 103 + __SOF_TIMESTAMPING_CNT, 104 + sof_timestamping_names, compact); 105 + if (ret < 0) 106 + return ret; 107 + } 108 + if (ts_info->tx_types) { 109 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_TX_TYPES, 110 + &ts_info->tx_types, NULL, 111 + __HWTSTAMP_TX_CNT, 112 + ts_tx_type_names, compact); 113 + if (ret < 0) 114 + return ret; 115 + } 116 + if (ts_info->rx_filters) { 117 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSINFO_RX_FILTERS, 118 + &ts_info->rx_filters, NULL, 119 + __HWTSTAMP_FILTER_CNT, 120 + ts_rx_filter_names, compact); 121 + if (ret < 0) 122 + return ret; 123 + } 124 + if (ts_info->phc_index >= 0 && 125 + nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX, ts_info->phc_index)) 126 + return -EMSGSIZE; 127 + 128 + return 0; 129 + } 130 + 131 + const struct ethnl_request_ops ethnl_tsinfo_request_ops = { 132 + .request_cmd = ETHTOOL_MSG_TSINFO_GET, 133 + .reply_cmd = ETHTOOL_MSG_TSINFO_GET_REPLY, 134 + .hdr_attr = ETHTOOL_A_TSINFO_HEADER, 135 + .max_attr = ETHTOOL_A_TSINFO_MAX, 136 + .req_info_size = sizeof(struct tsinfo_req_info), 137 + .reply_data_size = sizeof(struct tsinfo_reply_data), 138 + .request_policy = tsinfo_get_policy, 139 + 140 + .prepare_data = tsinfo_prepare_data, 141 + .reply_size = tsinfo_reply_size, 142 + .fill_reply = tsinfo_fill_reply, 143 + };