History

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.

Kory Maincent committed 1 year ago

Commit 6e9e2ee1 parent b9e3f7d10 files · +655 −26Browse files

Unified · Split

10 files
  1. Documentation/netlink/specs/ethtool.yaml +56 −0
  2. Documentation/networking/ethtool-netlink.rst +75 −0
  3. Documentation/networking/timestamping.rst +24 −14
  4. include/uapi/linux/ethtool_netlink_generated.h +16 −0
  5. net/ethtool/Makefile +1 −1
  6. net/ethtool/common.c +17 −10
  7. net/ethtool/common.h +1 −1
  8. net/ethtool/netlink.c +18 −0
  9. net/ethtool/netlink.h +3 −0
  10. net/ethtool/tsconfig.c +444 −0
Documentation/netlink/specs/ethtool.yaml+56−0
@@ -1489,6 +1489,33 @@ attribute-sets: · 1488 unmodified lines
14891489 -
14901490 name: downstream-sfp-name
14911491 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
14921519
14931520 operations:
14941521 enum-model: directional
@@ -2314,3 +2341,32 @@ operations: · 819 unmodified lines
23142341 name: phy-ntf
23152342 doc: Notification for change in PHY devices.
23162343 notify: phy-get
2344+ -
2345+ name: tsconfig-get
2346+ doc: Get hwtstamp config.
2347+
2348+ attribute-set: tsconfig
2349+
2350+ do: &tsconfig-get-op
2351+ request:
2352+ attributes:
2353+ - header
2354+ reply:
2355+ attributes: &tsconfig
2356+ - header
2357+ - hwtstamp-provider
2358+ - tx-types
2359+ - rx-filters
2360+ - hwtstamp-flags
2361+ dump: *tsconfig-get-op
2362+ -
2363+ name: tsconfig-set
2364+ doc: Set hwtstamp config.
2365+
2366+ attribute-set: tsconfig
2367+
2368+ do:
2369+ request:
2370+ attributes: *tsconfig
2371+ reply:
2372+ attributes: *tsconfig
Documentation/networking/ethtool-netlink.rst+75−0
@@ -237,6 +237,8 @@ Userspace to kernel: · 236 unmodified lines
237237 ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters
238238 ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware
239239 ``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
240242 ===================================== =================================
241243
242244 Kernel to userspace:
@@ -286,6 +288,8 @@ Kernel to userspace: · 43 unmodified lines
286288 ``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates
287289 ``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information
288290 ``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change
291+ ``ETHTOOL_MSG_TSCONFIG_GET_REPLY`` hw timestamping configuration
292+ ``ETHTOOL_MSG_TSCONFIG_SET_REPLY`` new hw timestamping configuration
289293 ======================================== =================================
290294
291295 ``GET`` requests are sent by userspace applications to retrieve device
@@ -2244,6 +2248,75 @@ Kernel response contents: · 1952 unmodified lines
22442248 When ``ETHTOOL_A_PHY_UPSTREAM_TYPE`` is PHY_UPSTREAM_PHY, the PHY's parent is
22452249 another PHY.
22462250
2251+TSCONFIG_GET
2252+============
2253+
2254+Retrieves the information about the current hardware timestamping source and
2255+configuration.
2256+
2257+It is similar to the deprecated ``SIOCGHWTSTAMP`` ioctl request.
2258+
2259+Request contents:
2260+
2261+ ==================================== ====== ==========================
2262+ ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
2263+ ==================================== ====== ==========================
2264+
2265+Kernel response contents:
2266+
2267+ ======================================== ====== ============================
2268+ ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
2269+ ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
2270+ ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
2271+ ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
2272+ ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
2273+ ======================================== ====== ============================
2274+
2275+When set the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` attribute identifies the
2276+source of the hw timestamping provider. It is composed by
2277+``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX`` attribute which describe the index of
2278+the PTP device and ``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER`` which describe
2279+the qualifier of the timestamp.
2280+
2281+When set the ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS``
2282+and the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` attributes identify the Tx
2283+type, the Rx filter and the flags configured for the current hw timestamping
2284+provider. The attributes are propagated to the driver through the following
2285+structure:
2286+
2287+.. kernel-doc:: include/linux/net_tstamp.h
2288+ :identifiers: kernel_hwtstamp_config
2289+
2290+TSCONFIG_SET
2291+============
2292+
2293+Set the information about the current hardware timestamping source and
2294+configuration.
2295+
2296+It is similar to the deprecated ``SIOCSHWTSTAMP`` ioctl request.
2297+
2298+Request contents:
2299+
2300+ ======================================== ====== ============================
2301+ ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
2302+ ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
2303+ ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
2304+ ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
2305+ ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
2306+ ======================================== ====== ============================
2307+
2308+Kernel response contents:
2309+
2310+ ======================================== ====== ============================
2311+ ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header
2312+ ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
2313+ ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type
2314+ ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter
2315+ ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags
2316+ ======================================== ====== ============================
2317+
2318+For a description of each attribute, see ``TSCONFIG_GET``.
2319+
22472320 Request translation
22482321 ===================
22492322
@@ -2352,4 +2425,6 @@ are netlink only. · 102 unmodified lines
23522425 n/a ``ETHTOOL_MSG_MM_SET``
23532426 n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT``
23542427 n/a ``ETHTOOL_MSG_PHY_GET``
2428+ ``SIOCGHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_GET``
2429+ ``SIOCSHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_SET``
23552430 =================================== =====================================
Documentation/networking/timestamping.rst+24−14
@@ -525,8 +525,8 @@ implicitly defined. ts[0] holds a software timestamp if set, ts[1] · 524 unmodified lines
525525 is again deprecated and ts[2] holds a hardware timestamp if set.
526526
527527
528−3. Hardware Timestamping configuration: SIOCSHWTSTAMP and SIOCGHWTSTAMP
529−=======================================================================
528+3. Hardware Timestamping configuration: ETHTOOL_MSG_TSCONFIG_SET/GET
529+====================================================================
530530
531531 Hardware time stamping must also be initialized for each device driver
532532 that is expected to do hardware time stamping. The parameter is defined in
@@ -539,12 +539,14 @@ include/uapi/linux/net_tstamp.h as:: · 6 unmodified lines
539539 };
540540
541541 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.
548550
549551 Drivers are free to use a more permissive configuration than the requested
550552 configuration. It is expected that drivers should only implement directly the
@@ -563,9 +565,16 @@ Only a processes with admin rights may change the configuration. User · 12 unmodified lines
563565 space is responsible to ensure that multiple processes don't interfere
564566 with each other and that the settings are reset.
565567
566−Any process can read the actual configuration by passing this
567−structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has
568−not been implemented in all drivers.
568+Any process can read the actual configuration by requesting tsconfig netlink
569+socket ``ETHTOOL_MSG_TSCONFIG_GET``.
570+
571+The legacy configuration is the use of the ioctl(SIOCSHWTSTAMP) with a pointer
572+to a struct ifreq whose ifr_data points to a struct hwtstamp_config.
573+The tx_type and rx_filter are hints to the driver what it is expected to do.
574+If the requested fine-grained filtering for incoming packets is not
575+supported, the driver may time stamp more than just the requested types
576+of packets. ioctl(SIOCGHWTSTAMP) is used in the same way as the
577+ioctl(SIOCSHWTSTAMP). However, this has not been implemented in all drivers.
569578
570579 ::
571580
@@ -610,9 +619,10 @@ not been implemented in all drivers. · 38 unmodified lines
610619 --------------------------------------------------------
611620
612621 A driver which supports hardware time stamping must support the
613−SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
614−the actual values as described in the section on SIOCSHWTSTAMP. It
615−should also support SIOCGHWTSTAMP.
622+ndo_hwtstamp_set NDO or the legacy SIOCSHWTSTAMP ioctl and update the
623+supplied struct hwtstamp_config with the actual values as described in
624+the section on SIOCSHWTSTAMP. It should also support ndo_hwtstamp_get or
625+the legacy SIOCGHWTSTAMP.
616626
617627 Time stamps for received packets must be stored in the skb. To get a pointer
618628 to the shared time stamp structure of the skb call skb_hwtstamps(). Then
include/uapi/linux/ethtool_netlink_generated.h+16−0
@@ -694,6 +694,18 @@ enum { · 693 unmodified lines
694694 ETHTOOL_A_PHY_MAX = (__ETHTOOL_A_PHY_CNT - 1)
695695 };
696696
697+enum {
698+ ETHTOOL_A_TSCONFIG_UNSPEC,
699+ ETHTOOL_A_TSCONFIG_HEADER,
700+ ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER,
701+ ETHTOOL_A_TSCONFIG_TX_TYPES,
702+ ETHTOOL_A_TSCONFIG_RX_FILTERS,
703+ ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS,
704+
705+ __ETHTOOL_A_TSCONFIG_CNT,
706+ ETHTOOL_A_TSCONFIG_MAX = (__ETHTOOL_A_TSCONFIG_CNT - 1)
707+};
708+
697709 enum {
698710 ETHTOOL_MSG_USER_NONE = 0,
699711 ETHTOOL_MSG_STRSET_GET = 1,
@@ -741,6 +753,8 @@ enum { · 41 unmodified lines
741753 ETHTOOL_MSG_MM_SET,
742754 ETHTOOL_MSG_MODULE_FW_FLASH_ACT,
743755 ETHTOOL_MSG_PHY_GET,
756+ ETHTOOL_MSG_TSCONFIG_GET,
757+ ETHTOOL_MSG_TSCONFIG_SET,
744758
745759 __ETHTOOL_MSG_USER_CNT,
746760 ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1)
@@ -794,6 +808,8 @@ enum { · 47 unmodified lines
794808 ETHTOOL_MSG_MODULE_FW_FLASH_NTF,
795809 ETHTOOL_MSG_PHY_GET_REPLY,
796810 ETHTOOL_MSG_PHY_NTF,
811+ ETHTOOL_MSG_TSCONFIG_GET_REPLY,
812+ ETHTOOL_MSG_TSCONFIG_SET_REPLY,
797813
798814 __ETHTOOL_MSG_KERNEL_CNT,
799815 ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1)
net/ethtool/Makefile+1−1
@@ -9,4 +9,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \ · 8 unmodified lines
99 channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
1010 tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
1111 module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o mm.o \
12− phy.o
12+ phy.o tsconfig.o
net/ethtool/common.c+17−10
@@ -797,7 +797,7 @@ int ethtool_net_get_ts_info_by_phc(struct net_device *dev, · 796 unmodified lines
797797 return -ENODEV;
798798 }
799799
800−int
800+struct phy_device *
801801 ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
802802 struct kernel_ethtool_ts_info *info,
803803 struct hwtstamp_provider_desc *hwprov_desc)
@@ -806,7 +806,7 @@ ethtool_phy_get_ts_info_by_phc(struct net_device *dev, · 2 unmodified lines
806806
807807 /* Only precise qualifier is supported in phydev */
808808 if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
809− return -ENODEV;
809+ return ERR_PTR(-ENODEV);
810810
811811 /* Look in the phy topology */
812812 if (dev->link_topo) {
@@ -820,12 +820,12 @@ ethtool_phy_get_ts_info_by_phc(struct net_device *dev, · 7 unmodified lines
820820 ethtool_init_tsinfo(info);
821821 err = phy_ts_info(pdn->phy, info);
822822 if (err)
823− return err;
823+ return ERR_PTR(err);
824824
825825 if (info->phc_index == hwprov_desc->index)
826− return 0;
826+ return pdn->phy;
827827 }
828− return -ENODEV;
828+ return ERR_PTR(-ENODEV);
829829 }
830830
831831 /* Look on the dev->phydev */
@@ -833,13 +833,13 @@ ethtool_phy_get_ts_info_by_phc(struct net_device *dev, · 1 unmodified line
833833 ethtool_init_tsinfo(info);
834834 err = phy_ts_info(dev->phydev, info);
835835 if (err)
836− return err;
836+ return ERR_PTR(err);
837837
838838 if (info->phc_index == hwprov_desc->index)
839− return 0;
839+ return dev->phydev;
840840 }
841841
842− return -ENODEV;
842+ return ERR_PTR(-ENODEV);
843843 }
844844
845845 int ethtool_get_ts_info_by_phc(struct net_device *dev,
@@ -849,8 +849,15 @@ int ethtool_get_ts_info_by_phc(struct net_device *dev, · 3 unmodified lines
849849 int err;
850850
851851 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+ }
854861
855862 info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
856863 SOF_TIMESTAMPING_SOFTWARE;
net/ethtool/common.h+1−1
@@ -56,7 +56,7 @@ int ethtool_get_ts_info_by_phc(struct net_device *dev, · 55 unmodified lines
5656 int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
5757 struct kernel_ethtool_ts_info *info,
5858 struct hwtstamp_provider_desc *hwprov_desc);
59−int
59+struct phy_device *
6060 ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
6161 struct kernel_ethtool_ts_info *info,
6262 struct hwtstamp_provider_desc *hwprov_desc);
net/ethtool/netlink.c+18−0
@@ -394,6 +394,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { · 393 unmodified lines
394394 [ETHTOOL_MSG_PLCA_GET_STATUS] = &ethnl_plca_status_request_ops,
395395 [ETHTOOL_MSG_MM_GET] = &ethnl_mm_request_ops,
396396 [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,
397399 };
398400
399401 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -1243,6 +1245,22 @@ static const struct genl_ops ethtool_genl_ops[] = { · 843 unmodified lines
12431245 .policy = ethnl_phy_get_policy,
12441246 .maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1,
12451247 },
1248+ {
1249+ .cmd = ETHTOOL_MSG_TSCONFIG_GET,
1250+ .doit = ethnl_default_doit,
1251+ .start = ethnl_default_start,
1252+ .dumpit = ethnl_default_dumpit,
1253+ .done = ethnl_default_done,
1254+ .policy = ethnl_tsconfig_get_policy,
1255+ .maxattr = ARRAY_SIZE(ethnl_tsconfig_get_policy) - 1,
1256+ },
1257+ {
1258+ .cmd = ETHTOOL_MSG_TSCONFIG_SET,
1259+ .flags = GENL_UNS_ADMIN_PERM,
1260+ .doit = ethnl_default_set_doit,
1261+ .policy = ethnl_tsconfig_set_policy,
1262+ .maxattr = ARRAY_SIZE(ethnl_tsconfig_set_policy) - 1,
1263+ },
12461264 };
12471265
12481266 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
net/ethtool/netlink.h+3−0
@@ -435,6 +435,7 @@ extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; · 434 unmodified lines
435435 extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
436436 extern const struct ethnl_request_ops ethnl_mm_request_ops;
437437 extern const struct ethnl_request_ops ethnl_phy_request_ops;
438+extern const struct ethnl_request_ops ethnl_tsconfig_request_ops;
438439
439440 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
440441 extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
@@ -485,6 +486,8 @@ extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1]; · 44 unmodified lines
485486 extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
486487 extern const struct nla_policy ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1];
487488 extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1];
489+extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1];
490+extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1];
488491
489492 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
490493 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
net/ethtool/tsconfig.c+444−0
@@ -0,0 +1,444 @@
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+};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t