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

net: ethtool: Add support for tsconfig command to get/set hwtstamp config

Introduce support for ETHTOOL_MSG_TSCONFIG_GET/SET ethtool netlink socket
to read and configure hwtstamp configuration of a PHC provider. Note that
simultaneous hwtstamp isn't supported; configuring a new one disables the
previous setting.

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Kory Maincent and committed by
David S. Miller
6e9e2eed b9e3f7dc

+655 -26
+56
Documentation/netlink/specs/ethtool.yaml
··· 1489 1489 - 1490 1490 name: downstream-sfp-name 1491 1491 type: string 1492 + - 1493 + name: tsconfig 1494 + attr-cnt-name: __ethtool-a-tsconfig-cnt 1495 + attributes: 1496 + - 1497 + name: unspec 1498 + type: unused 1499 + value: 0 1500 + - 1501 + name: header 1502 + type: nest 1503 + nested-attributes: header 1504 + - 1505 + name: hwtstamp-provider 1506 + type: nest 1507 + nested-attributes: ts-hwtstamp-provider 1508 + - 1509 + name: tx-types 1510 + type: nest 1511 + nested-attributes: bitset 1512 + - 1513 + name: rx-filters 1514 + type: nest 1515 + nested-attributes: bitset 1516 + - 1517 + name: hwtstamp-flags 1518 + type: u32 1492 1519 1493 1520 operations: 1494 1521 enum-model: directional ··· 2341 2314 name: phy-ntf 2342 2315 doc: Notification for change in PHY devices. 2343 2316 notify: phy-get 2317 + - 2318 + name: tsconfig-get 2319 + doc: Get hwtstamp config. 2320 + 2321 + attribute-set: tsconfig 2322 + 2323 + do: &tsconfig-get-op 2324 + request: 2325 + attributes: 2326 + - header 2327 + reply: 2328 + attributes: &tsconfig 2329 + - header 2330 + - hwtstamp-provider 2331 + - tx-types 2332 + - rx-filters 2333 + - hwtstamp-flags 2334 + dump: *tsconfig-get-op 2335 + - 2336 + name: tsconfig-set 2337 + doc: Set hwtstamp config. 2338 + 2339 + attribute-set: tsconfig 2340 + 2341 + do: 2342 + request: 2343 + attributes: *tsconfig 2344 + reply: 2345 + attributes: *tsconfig
+75
Documentation/networking/ethtool-netlink.rst
··· 237 237 ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters 238 238 ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware 239 239 ``ETHTOOL_MSG_PHY_GET`` get Ethernet PHY information 240 + ``ETHTOOL_MSG_TSCONFIG_GET`` get hw timestamping configuration 241 + ``ETHTOOL_MSG_TSCONFIG_SET`` set hw timestamping configuration 240 242 ===================================== ================================= 241 243 242 244 Kernel to userspace: ··· 288 286 ``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates 289 287 ``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information 290 288 ``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change 289 + ``ETHTOOL_MSG_TSCONFIG_GET_REPLY`` hw timestamping configuration 290 + ``ETHTOOL_MSG_TSCONFIG_SET_REPLY`` new hw timestamping configuration 291 291 ======================================== ================================= 292 292 293 293 ``GET`` requests are sent by userspace applications to retrieve device ··· 2248 2244 When ``ETHTOOL_A_PHY_UPSTREAM_TYPE`` is PHY_UPSTREAM_PHY, the PHY's parent is 2249 2245 another PHY. 2250 2246 2247 + TSCONFIG_GET 2248 + ============ 2249 + 2250 + Retrieves the information about the current hardware timestamping source and 2251 + configuration. 2252 + 2253 + It is similar to the deprecated ``SIOCGHWTSTAMP`` ioctl request. 2254 + 2255 + Request contents: 2256 + 2257 + ==================================== ====== ========================== 2258 + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header 2259 + ==================================== ====== ========================== 2260 + 2261 + Kernel response contents: 2262 + 2263 + ======================================== ====== ============================ 2264 + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header 2265 + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider 2266 + ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type 2267 + ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter 2268 + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags 2269 + ======================================== ====== ============================ 2270 + 2271 + When set the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` attribute identifies the 2272 + source of the hw timestamping provider. It is composed by 2273 + ``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX`` attribute which describe the index of 2274 + the PTP device and ``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER`` which describe 2275 + the qualifier of the timestamp. 2276 + 2277 + When set the ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` 2278 + and the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` attributes identify the Tx 2279 + type, the Rx filter and the flags configured for the current hw timestamping 2280 + provider. The attributes are propagated to the driver through the following 2281 + structure: 2282 + 2283 + .. kernel-doc:: include/linux/net_tstamp.h 2284 + :identifiers: kernel_hwtstamp_config 2285 + 2286 + TSCONFIG_SET 2287 + ============ 2288 + 2289 + Set the information about the current hardware timestamping source and 2290 + configuration. 2291 + 2292 + It is similar to the deprecated ``SIOCSHWTSTAMP`` ioctl request. 2293 + 2294 + Request contents: 2295 + 2296 + ======================================== ====== ============================ 2297 + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header 2298 + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider 2299 + ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type 2300 + ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter 2301 + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags 2302 + ======================================== ====== ============================ 2303 + 2304 + Kernel response contents: 2305 + 2306 + ======================================== ====== ============================ 2307 + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header 2308 + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider 2309 + ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type 2310 + ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter 2311 + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags 2312 + ======================================== ====== ============================ 2313 + 2314 + For a description of each attribute, see ``TSCONFIG_GET``. 2315 + 2251 2316 Request translation 2252 2317 =================== 2253 2318 ··· 2425 2352 n/a ``ETHTOOL_MSG_MM_SET`` 2426 2353 n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` 2427 2354 n/a ``ETHTOOL_MSG_PHY_GET`` 2355 + ``SIOCGHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_GET`` 2356 + ``SIOCSHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_SET`` 2428 2357 =================================== =====================================
+24 -14
Documentation/networking/timestamping.rst
··· 525 525 is again deprecated and ts[2] holds a hardware timestamp if set. 526 526 527 527 528 - 3. Hardware Timestamping configuration: SIOCSHWTSTAMP and SIOCGHWTSTAMP 529 - ======================================================================= 528 + 3. Hardware Timestamping configuration: ETHTOOL_MSG_TSCONFIG_SET/GET 529 + ==================================================================== 530 530 531 531 Hardware time stamping must also be initialized for each device driver 532 532 that is expected to do hardware time stamping. The parameter is defined in ··· 539 539 }; 540 540 541 541 Desired behavior is passed into the kernel and to a specific device by 542 - calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose 543 - ifr_data points to a struct hwtstamp_config. The tx_type and 544 - rx_filter are hints to the driver what it is expected to do. If 545 - the requested fine-grained filtering for incoming packets is not 546 - supported, the driver may time stamp more than just the requested types 547 - of packets. 542 + calling the tsconfig netlink socket ``ETHTOOL_MSG_TSCONFIG_SET``. 543 + The ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` and 544 + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` netlink attributes are then used to set 545 + the struct hwtstamp_config accordingly. 546 + 547 + The ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` netlink nested attribute is used 548 + to select the source of the hardware time stamping. It is composed of an index 549 + for the device source and a qualifier for the type of time stamping. 548 550 549 551 Drivers are free to use a more permissive configuration than the requested 550 552 configuration. It is expected that drivers should only implement directly the ··· 565 563 space is responsible to ensure that multiple processes don't interfere 566 564 with each other and that the settings are reset. 567 565 568 - Any process can read the actual configuration by passing this 569 - structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has 570 - not been implemented in all drivers. 566 + Any process can read the actual configuration by requesting tsconfig netlink 567 + socket ``ETHTOOL_MSG_TSCONFIG_GET``. 568 + 569 + The legacy configuration is the use of the ioctl(SIOCSHWTSTAMP) with a pointer 570 + to a struct ifreq whose ifr_data points to a struct hwtstamp_config. 571 + The tx_type and rx_filter are hints to the driver what it is expected to do. 572 + If the requested fine-grained filtering for incoming packets is not 573 + supported, the driver may time stamp more than just the requested types 574 + of packets. ioctl(SIOCGHWTSTAMP) is used in the same way as the 575 + ioctl(SIOCSHWTSTAMP). However, this has not been implemented in all drivers. 571 576 572 577 :: 573 578 ··· 619 610 -------------------------------------------------------- 620 611 621 612 A driver which supports hardware time stamping must support the 622 - SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with 623 - the actual values as described in the section on SIOCSHWTSTAMP. It 624 - should also support SIOCGHWTSTAMP. 613 + ndo_hwtstamp_set NDO or the legacy SIOCSHWTSTAMP ioctl and update the 614 + supplied struct hwtstamp_config with the actual values as described in 615 + the section on SIOCSHWTSTAMP. It should also support ndo_hwtstamp_get or 616 + the legacy SIOCGHWTSTAMP. 625 617 626 618 Time stamps for received packets must be stored in the skb. To get a pointer 627 619 to the shared time stamp structure of the skb call skb_hwtstamps(). Then
+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 mm.o \ 12 - phy.o 12 + phy.o tsconfig.o
+17 -10
net/ethtool/common.c
··· 797 797 return -ENODEV; 798 798 } 799 799 800 - int 800 + struct phy_device * 801 801 ethtool_phy_get_ts_info_by_phc(struct net_device *dev, 802 802 struct kernel_ethtool_ts_info *info, 803 803 struct hwtstamp_provider_desc *hwprov_desc) ··· 806 806 807 807 /* Only precise qualifier is supported in phydev */ 808 808 if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE) 809 - return -ENODEV; 809 + return ERR_PTR(-ENODEV); 810 810 811 811 /* Look in the phy topology */ 812 812 if (dev->link_topo) { ··· 820 820 ethtool_init_tsinfo(info); 821 821 err = phy_ts_info(pdn->phy, info); 822 822 if (err) 823 - return err; 823 + return ERR_PTR(err); 824 824 825 825 if (info->phc_index == hwprov_desc->index) 826 - return 0; 826 + return pdn->phy; 827 827 } 828 - return -ENODEV; 828 + return ERR_PTR(-ENODEV); 829 829 } 830 830 831 831 /* Look on the dev->phydev */ ··· 833 833 ethtool_init_tsinfo(info); 834 834 err = phy_ts_info(dev->phydev, info); 835 835 if (err) 836 - return err; 836 + return ERR_PTR(err); 837 837 838 838 if (info->phc_index == hwprov_desc->index) 839 - return 0; 839 + return dev->phydev; 840 840 } 841 841 842 - return -ENODEV; 842 + return ERR_PTR(-ENODEV); 843 843 } 844 844 845 845 int ethtool_get_ts_info_by_phc(struct net_device *dev, ··· 849 849 int err; 850 850 851 851 err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc); 852 - if (err == -ENODEV) 853 - err = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc); 852 + if (err == -ENODEV) { 853 + struct phy_device *phy; 854 + 855 + phy = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc); 856 + if (IS_ERR(phy)) 857 + err = PTR_ERR(phy); 858 + else 859 + err = 0; 860 + } 854 861 855 862 info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE | 856 863 SOF_TIMESTAMPING_SOFTWARE;
+1 -1
net/ethtool/common.h
··· 56 56 int ethtool_net_get_ts_info_by_phc(struct net_device *dev, 57 57 struct kernel_ethtool_ts_info *info, 58 58 struct hwtstamp_provider_desc *hwprov_desc); 59 - int 59 + struct phy_device * 60 60 ethtool_phy_get_ts_info_by_phc(struct net_device *dev, 61 61 struct kernel_ethtool_ts_info *info, 62 62 struct hwtstamp_provider_desc *hwprov_desc);
+18
net/ethtool/netlink.c
··· 394 394 [ETHTOOL_MSG_PLCA_GET_STATUS] = &ethnl_plca_status_request_ops, 395 395 [ETHTOOL_MSG_MM_GET] = &ethnl_mm_request_ops, 396 396 [ETHTOOL_MSG_MM_SET] = &ethnl_mm_request_ops, 397 + [ETHTOOL_MSG_TSCONFIG_GET] = &ethnl_tsconfig_request_ops, 398 + [ETHTOOL_MSG_TSCONFIG_SET] = &ethnl_tsconfig_request_ops, 397 399 }; 398 400 399 401 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) ··· 1244 1242 .done = ethnl_phy_done, 1245 1243 .policy = ethnl_phy_get_policy, 1246 1244 .maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1, 1245 + }, 1246 + { 1247 + .cmd = ETHTOOL_MSG_TSCONFIG_GET, 1248 + .doit = ethnl_default_doit, 1249 + .start = ethnl_default_start, 1250 + .dumpit = ethnl_default_dumpit, 1251 + .done = ethnl_default_done, 1252 + .policy = ethnl_tsconfig_get_policy, 1253 + .maxattr = ARRAY_SIZE(ethnl_tsconfig_get_policy) - 1, 1254 + }, 1255 + { 1256 + .cmd = ETHTOOL_MSG_TSCONFIG_SET, 1257 + .flags = GENL_UNS_ADMIN_PERM, 1258 + .doit = ethnl_default_set_doit, 1259 + .policy = ethnl_tsconfig_set_policy, 1260 + .maxattr = ARRAY_SIZE(ethnl_tsconfig_set_policy) - 1, 1247 1261 }, 1248 1262 }; 1249 1263
+3
net/ethtool/netlink.h
··· 435 435 extern const struct ethnl_request_ops ethnl_plca_status_request_ops; 436 436 extern const struct ethnl_request_ops ethnl_mm_request_ops; 437 437 extern const struct ethnl_request_ops ethnl_phy_request_ops; 438 + extern const struct ethnl_request_ops ethnl_tsconfig_request_ops; 438 439 439 440 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; 440 441 extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; ··· 486 485 extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; 487 486 extern const struct nla_policy ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1]; 488 487 extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1]; 488 + extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1]; 489 + extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1]; 489 490 490 491 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); 491 492 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
+444
net/ethtool/tsconfig.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/net_tstamp.h> 4 + #include <linux/ptp_clock_kernel.h> 5 + 6 + #include "netlink.h" 7 + #include "common.h" 8 + #include "bitset.h" 9 + #include "../core/dev.h" 10 + #include "ts.h" 11 + 12 + struct tsconfig_req_info { 13 + struct ethnl_req_info base; 14 + }; 15 + 16 + struct tsconfig_reply_data { 17 + struct ethnl_reply_data base; 18 + struct hwtstamp_provider_desc hwprov_desc; 19 + struct { 20 + u32 tx_type; 21 + u32 rx_filter; 22 + u32 flags; 23 + } hwtst_config; 24 + }; 25 + 26 + #define TSCONFIG_REPDATA(__reply_base) \ 27 + container_of(__reply_base, struct tsconfig_reply_data, base) 28 + 29 + const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1] = { 30 + [ETHTOOL_A_TSCONFIG_HEADER] = 31 + NLA_POLICY_NESTED(ethnl_header_policy), 32 + }; 33 + 34 + static int tsconfig_prepare_data(const struct ethnl_req_info *req_base, 35 + struct ethnl_reply_data *reply_base, 36 + const struct genl_info *info) 37 + { 38 + struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base); 39 + struct hwtstamp_provider *hwprov = NULL; 40 + struct net_device *dev = reply_base->dev; 41 + struct kernel_hwtstamp_config cfg = {}; 42 + int ret; 43 + 44 + if (!dev->netdev_ops->ndo_hwtstamp_get) 45 + return -EOPNOTSUPP; 46 + 47 + ret = ethnl_ops_begin(dev); 48 + if (ret < 0) 49 + return ret; 50 + 51 + ret = dev_get_hwtstamp_phylib(dev, &cfg); 52 + if (ret) 53 + goto out; 54 + 55 + data->hwtst_config.tx_type = BIT(cfg.tx_type); 56 + data->hwtst_config.rx_filter = BIT(cfg.rx_filter); 57 + data->hwtst_config.flags = BIT(cfg.flags); 58 + 59 + data->hwprov_desc.index = -1; 60 + hwprov = rtnl_dereference(dev->hwprov); 61 + if (hwprov) { 62 + data->hwprov_desc.index = hwprov->desc.index; 63 + data->hwprov_desc.qualifier = hwprov->desc.qualifier; 64 + } else { 65 + struct kernel_ethtool_ts_info ts_info = {}; 66 + 67 + ts_info.phc_index = -1; 68 + ret = __ethtool_get_ts_info(dev, &ts_info); 69 + if (ret) 70 + goto out; 71 + 72 + if (ts_info.phc_index == -1) 73 + return -ENODEV; 74 + 75 + data->hwprov_desc.index = ts_info.phc_index; 76 + data->hwprov_desc.qualifier = ts_info.phc_qualifier; 77 + } 78 + 79 + out: 80 + ethnl_ops_complete(dev); 81 + return ret; 82 + } 83 + 84 + static int tsconfig_reply_size(const struct ethnl_req_info *req_base, 85 + const struct ethnl_reply_data *reply_base) 86 + { 87 + const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base); 88 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 89 + int len = 0; 90 + int ret; 91 + 92 + BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32); 93 + BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32); 94 + 95 + if (data->hwtst_config.flags) 96 + /* _TSCONFIG_HWTSTAMP_FLAGS */ 97 + len += nla_total_size(sizeof(u32)); 98 + 99 + if (data->hwtst_config.tx_type) { 100 + ret = ethnl_bitset32_size(&data->hwtst_config.tx_type, 101 + NULL, __HWTSTAMP_TX_CNT, 102 + ts_tx_type_names, compact); 103 + if (ret < 0) 104 + return ret; 105 + len += ret; /* _TSCONFIG_TX_TYPES */ 106 + } 107 + if (data->hwtst_config.rx_filter) { 108 + ret = ethnl_bitset32_size(&data->hwtst_config.rx_filter, 109 + NULL, __HWTSTAMP_FILTER_CNT, 110 + ts_rx_filter_names, compact); 111 + if (ret < 0) 112 + return ret; 113 + len += ret; /* _TSCONFIG_RX_FILTERS */ 114 + } 115 + 116 + if (data->hwprov_desc.index >= 0) 117 + /* _TSCONFIG_HWTSTAMP_PROVIDER */ 118 + len += nla_total_size(0) + 119 + 2 * nla_total_size(sizeof(u32)); 120 + 121 + return len; 122 + } 123 + 124 + static int tsconfig_fill_reply(struct sk_buff *skb, 125 + const struct ethnl_req_info *req_base, 126 + const struct ethnl_reply_data *reply_base) 127 + { 128 + const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base); 129 + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 130 + int ret; 131 + 132 + if (data->hwtst_config.flags) { 133 + ret = nla_put_u32(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS, 134 + data->hwtst_config.flags); 135 + if (ret < 0) 136 + return ret; 137 + } 138 + 139 + if (data->hwtst_config.tx_type) { 140 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_TX_TYPES, 141 + &data->hwtst_config.tx_type, NULL, 142 + __HWTSTAMP_TX_CNT, 143 + ts_tx_type_names, compact); 144 + if (ret < 0) 145 + return ret; 146 + } 147 + 148 + if (data->hwtst_config.rx_filter) { 149 + ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_RX_FILTERS, 150 + &data->hwtst_config.rx_filter, 151 + NULL, __HWTSTAMP_FILTER_CNT, 152 + ts_rx_filter_names, compact); 153 + if (ret < 0) 154 + return ret; 155 + } 156 + 157 + if (data->hwprov_desc.index >= 0) { 158 + struct nlattr *nest; 159 + 160 + nest = nla_nest_start(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER); 161 + if (!nest) 162 + return -EMSGSIZE; 163 + 164 + if (nla_put_u32(skb, ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX, 165 + data->hwprov_desc.index) || 166 + nla_put_u32(skb, 167 + ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER, 168 + data->hwprov_desc.qualifier)) { 169 + nla_nest_cancel(skb, nest); 170 + return -EMSGSIZE; 171 + } 172 + 173 + nla_nest_end(skb, nest); 174 + } 175 + return 0; 176 + } 177 + 178 + /* TSCONFIG_SET */ 179 + const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1] = { 180 + [ETHTOOL_A_TSCONFIG_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), 181 + [ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER] = 182 + NLA_POLICY_NESTED(ethnl_ts_hwtst_prov_policy), 183 + [ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS] = { .type = NLA_U32 }, 184 + [ETHTOOL_A_TSCONFIG_RX_FILTERS] = { .type = NLA_NESTED }, 185 + [ETHTOOL_A_TSCONFIG_TX_TYPES] = { .type = NLA_NESTED }, 186 + }; 187 + 188 + static int tsconfig_send_reply(struct net_device *dev, struct genl_info *info) 189 + { 190 + struct tsconfig_reply_data *reply_data; 191 + struct tsconfig_req_info *req_info; 192 + struct sk_buff *rskb; 193 + void *reply_payload; 194 + int reply_len = 0; 195 + int ret; 196 + 197 + req_info = kzalloc(sizeof(*req_info), GFP_KERNEL); 198 + if (!req_info) 199 + return -ENOMEM; 200 + reply_data = kmalloc(sizeof(*reply_data), GFP_KERNEL); 201 + if (!reply_data) { 202 + kfree(req_info); 203 + return -ENOMEM; 204 + } 205 + 206 + ASSERT_RTNL(); 207 + reply_data->base.dev = dev; 208 + ret = tsconfig_prepare_data(&req_info->base, &reply_data->base, info); 209 + if (ret < 0) 210 + goto err_cleanup; 211 + 212 + ret = tsconfig_reply_size(&req_info->base, &reply_data->base); 213 + if (ret < 0) 214 + goto err_cleanup; 215 + 216 + reply_len = ret + ethnl_reply_header_size(); 217 + rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_TSCONFIG_SET_REPLY, 218 + ETHTOOL_A_TSCONFIG_HEADER, info, &reply_payload); 219 + if (!rskb) 220 + goto err_cleanup; 221 + 222 + ret = tsconfig_fill_reply(rskb, &req_info->base, &reply_data->base); 223 + if (ret < 0) 224 + goto err_cleanup; 225 + 226 + genlmsg_end(rskb, reply_payload); 227 + ret = genlmsg_reply(rskb, info); 228 + 229 + err_cleanup: 230 + kfree(reply_data); 231 + kfree(req_info); 232 + return ret; 233 + } 234 + 235 + static int ethnl_set_tsconfig_validate(struct ethnl_req_info *req_base, 236 + struct genl_info *info) 237 + { 238 + const struct net_device_ops *ops = req_base->dev->netdev_ops; 239 + 240 + if (!ops->ndo_hwtstamp_set || !ops->ndo_hwtstamp_get) 241 + return -EOPNOTSUPP; 242 + 243 + return 1; 244 + } 245 + 246 + static struct hwtstamp_provider * 247 + tsconfig_set_hwprov_from_desc(struct net_device *dev, 248 + struct genl_info *info, 249 + struct hwtstamp_provider_desc *hwprov_desc) 250 + { 251 + struct kernel_ethtool_ts_info ts_info; 252 + struct hwtstamp_provider *hwprov; 253 + struct nlattr **tb = info->attrs; 254 + struct phy_device *phy = NULL; 255 + enum hwtstamp_source source; 256 + int ret; 257 + 258 + ret = ethtool_net_get_ts_info_by_phc(dev, &ts_info, hwprov_desc); 259 + if (!ret) { 260 + /* Found */ 261 + source = HWTSTAMP_SOURCE_NETDEV; 262 + } else { 263 + phy = ethtool_phy_get_ts_info_by_phc(dev, &ts_info, hwprov_desc); 264 + if (IS_ERR(phy)) { 265 + if (PTR_ERR(phy) == -ENODEV) 266 + NL_SET_ERR_MSG_ATTR(info->extack, 267 + tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER], 268 + "phc not in this net device topology"); 269 + return ERR_CAST(phy); 270 + } 271 + 272 + source = HWTSTAMP_SOURCE_PHYLIB; 273 + } 274 + 275 + hwprov = kzalloc(sizeof(*hwprov), GFP_KERNEL); 276 + if (!hwprov) 277 + return ERR_PTR(-ENOMEM); 278 + 279 + hwprov->desc.index = hwprov_desc->index; 280 + hwprov->desc.qualifier = hwprov_desc->qualifier; 281 + hwprov->source = source; 282 + hwprov->phydev = phy; 283 + 284 + return hwprov; 285 + } 286 + 287 + static int ethnl_set_tsconfig(struct ethnl_req_info *req_base, 288 + struct genl_info *info) 289 + { 290 + struct kernel_hwtstamp_config hwtst_config = {0}; 291 + bool hwprov_mod = false, config_mod = false; 292 + struct hwtstamp_provider *hwprov = NULL; 293 + struct net_device *dev = req_base->dev; 294 + struct nlattr **tb = info->attrs; 295 + int ret; 296 + 297 + BUILD_BUG_ON(__HWTSTAMP_TX_CNT >= 32); 298 + BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT >= 32); 299 + 300 + if (!netif_device_present(dev)) 301 + return -ENODEV; 302 + 303 + if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER]) { 304 + struct hwtstamp_provider_desc __hwprov_desc = {.index = -1}; 305 + struct hwtstamp_provider *__hwprov; 306 + 307 + __hwprov = rtnl_dereference(dev->hwprov); 308 + if (__hwprov) { 309 + __hwprov_desc.index = __hwprov->desc.index; 310 + __hwprov_desc.qualifier = __hwprov->desc.qualifier; 311 + } 312 + 313 + ret = ts_parse_hwtst_provider(tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER], 314 + &__hwprov_desc, info->extack, 315 + &hwprov_mod); 316 + if (ret < 0) 317 + return ret; 318 + 319 + if (hwprov_mod) { 320 + hwprov = tsconfig_set_hwprov_from_desc(dev, info, 321 + &__hwprov_desc); 322 + if (IS_ERR(hwprov)) 323 + return PTR_ERR(hwprov); 324 + } 325 + } 326 + 327 + /* Get current hwtstamp config if we are not changing the 328 + * hwtstamp source. It will be zeroed in the other case. 329 + */ 330 + if (!hwprov_mod) { 331 + ret = dev_get_hwtstamp_phylib(dev, &hwtst_config); 332 + if (ret < 0 && ret != -EOPNOTSUPP) 333 + goto err_free_hwprov; 334 + } 335 + 336 + /* Get the hwtstamp config from netlink */ 337 + if (tb[ETHTOOL_A_TSCONFIG_TX_TYPES]) { 338 + u32 req_tx_type; 339 + 340 + req_tx_type = BIT(hwtst_config.tx_type); 341 + ret = ethnl_update_bitset32(&req_tx_type, 342 + __HWTSTAMP_TX_CNT, 343 + tb[ETHTOOL_A_TSCONFIG_TX_TYPES], 344 + ts_tx_type_names, info->extack, 345 + &config_mod); 346 + if (ret < 0) 347 + goto err_free_hwprov; 348 + 349 + /* Select only one tx type at a time */ 350 + if (ffs(req_tx_type) != fls(req_tx_type)) { 351 + ret = -EINVAL; 352 + goto err_free_hwprov; 353 + } 354 + 355 + hwtst_config.tx_type = ffs(req_tx_type) - 1; 356 + } 357 + 358 + if (tb[ETHTOOL_A_TSCONFIG_RX_FILTERS]) { 359 + u32 req_rx_filter; 360 + 361 + req_rx_filter = BIT(hwtst_config.rx_filter); 362 + ret = ethnl_update_bitset32(&req_rx_filter, 363 + __HWTSTAMP_FILTER_CNT, 364 + tb[ETHTOOL_A_TSCONFIG_RX_FILTERS], 365 + ts_rx_filter_names, info->extack, 366 + &config_mod); 367 + if (ret < 0) 368 + goto err_free_hwprov; 369 + 370 + /* Select only one rx filter at a time */ 371 + if (ffs(req_rx_filter) != fls(req_rx_filter)) { 372 + ret = -EINVAL; 373 + goto err_free_hwprov; 374 + } 375 + 376 + hwtst_config.rx_filter = ffs(req_rx_filter) - 1; 377 + } 378 + 379 + if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS]) { 380 + ethnl_update_u32(&hwtst_config.flags, 381 + tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS], 382 + &config_mod); 383 + } 384 + 385 + ret = net_hwtstamp_validate(&hwtst_config); 386 + if (ret) 387 + goto err_free_hwprov; 388 + 389 + if (hwprov_mod) { 390 + struct kernel_hwtstamp_config zero_config = {0}; 391 + struct hwtstamp_provider *__hwprov; 392 + 393 + /* Disable current time stamping if we try to enable 394 + * another one 395 + */ 396 + ret = dev_set_hwtstamp_phylib(dev, &zero_config, info->extack); 397 + if (ret < 0) 398 + goto err_free_hwprov; 399 + 400 + /* Change the selected hwtstamp source */ 401 + __hwprov = rcu_replace_pointer_rtnl(dev->hwprov, hwprov); 402 + if (__hwprov) 403 + kfree_rcu(__hwprov, rcu_head); 404 + } 405 + 406 + if (config_mod) { 407 + ret = dev_set_hwtstamp_phylib(dev, &hwtst_config, 408 + info->extack); 409 + if (ret < 0) 410 + return ret; 411 + } 412 + 413 + if (hwprov_mod || config_mod) { 414 + ret = tsconfig_send_reply(dev, info); 415 + if (ret && ret != -EOPNOTSUPP) { 416 + NL_SET_ERR_MSG(info->extack, 417 + "error while reading the new configuration set"); 418 + return ret; 419 + } 420 + } 421 + 422 + /* tsconfig has no notification */ 423 + return 0; 424 + 425 + err_free_hwprov: 426 + kfree(hwprov); 427 + 428 + return ret; 429 + } 430 + 431 + const struct ethnl_request_ops ethnl_tsconfig_request_ops = { 432 + .request_cmd = ETHTOOL_MSG_TSCONFIG_GET, 433 + .reply_cmd = ETHTOOL_MSG_TSCONFIG_GET_REPLY, 434 + .hdr_attr = ETHTOOL_A_TSCONFIG_HEADER, 435 + .req_info_size = sizeof(struct tsconfig_req_info), 436 + .reply_data_size = sizeof(struct tsconfig_reply_data), 437 + 438 + .prepare_data = tsconfig_prepare_data, 439 + .reply_size = tsconfig_reply_size, 440 + .fill_reply = tsconfig_fill_reply, 441 + 442 + .set_validate = ethnl_set_tsconfig_validate, 443 + .set = ethnl_set_tsconfig, 444 + };