net: ethtool: Add a command to expose current time stamping layer
authorKory Maincent <kory.maincent@bootlin.com>
Tue, 14 Nov 2023 11:28:36 +0000 (12:28 +0100)
committerDavid S. Miller <davem@davemloft.net>
Sat, 18 Nov 2023 14:52:57 +0000 (14:52 +0000)
Time stamping on network packets may happen either in the MAC or in
the PHY, but not both.  In preparation for making the choice
selectable, expose both the current layers via ethtool.

In accordance with the kernel implementation as it stands, the current
layer will always read as "phy" when a PHY time stamping device is
present. Future patches will allow changing the current layer
administratively.

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/networking/ethtool-netlink.rst
include/uapi/linux/ethtool_netlink.h
include/uapi/linux/net_tstamp.h
net/ethtool/Makefile
net/ethtool/common.h
net/ethtool/netlink.c
net/ethtool/netlink.h
net/ethtool/ts.c [new file with mode: 0644]

index 2540c70952ff21e60a2708d4d58f8a38335085f6..644b3b764044e37c03aef97403c5a5b8cdc2e969 100644 (file)
@@ -225,6 +225,7 @@ Userspace to kernel:
   ``ETHTOOL_MSG_RSS_GET``               get RSS settings
   ``ETHTOOL_MSG_MM_GET``                get MAC merge layer state
   ``ETHTOOL_MSG_MM_SET``                set MAC merge layer parameters
+  ``ETHTOOL_MSG_TS_GET``                get current timestamping
   ===================================== =================================
 
 Kernel to userspace:
@@ -268,6 +269,7 @@ Kernel to userspace:
   ``ETHTOOL_MSG_PSE_GET_REPLY``            PSE parameters
   ``ETHTOOL_MSG_RSS_GET_REPLY``            RSS settings
   ``ETHTOOL_MSG_MM_GET_REPLY``             MAC merge layer status
+  ``ETHTOOL_MSG_TS_GET_REPLY``             current timestamping
   ======================================== =================================
 
 ``GET`` requests are sent by userspace applications to retrieve device
@@ -1994,6 +1996,26 @@ The attributes are propagated to the driver through the following structure:
 .. kernel-doc:: include/linux/ethtool.h
     :identifiers: ethtool_mm_cfg
 
+TS_GET
+======
+
+Gets current timestamping.
+
+Request contents:
+
+  =================================  ======  ====================
+  ``ETHTOOL_A_TS_HEADER``            nested  request header
+  =================================  ======  ====================
+
+Kernel response contents:
+
+  =======================  ======  ==============================
+  ``ETHTOOL_A_TS_HEADER``  nested  reply header
+  ``ETHTOOL_A_TS_LAYER``   u32     current timestamping
+  =======================  ======  ==============================
+
+This command get the current timestamp layer.
+
 Request translation
 ===================
 
@@ -2100,4 +2122,5 @@ are netlink only.
   n/a                                 ``ETHTOOL_MSG_PLCA_GET_STATUS``
   n/a                                 ``ETHTOOL_MSG_MM_GET``
   n/a                                 ``ETHTOOL_MSG_MM_SET``
+  n/a                                 ``ETHTOOL_MSG_TS_GET``
   =================================== =====================================
index 73e2c10dc2cc30816ee9668cc05432e2a806fcff..cb51136328cfe29db1974ff6688cfb5587a5a556 100644 (file)
@@ -57,6 +57,7 @@ enum {
        ETHTOOL_MSG_PLCA_GET_STATUS,
        ETHTOOL_MSG_MM_GET,
        ETHTOOL_MSG_MM_SET,
+       ETHTOOL_MSG_TS_GET,
 
        /* add new constants above here */
        __ETHTOOL_MSG_USER_CNT,
@@ -109,6 +110,7 @@ enum {
        ETHTOOL_MSG_PLCA_NTF,
        ETHTOOL_MSG_MM_GET_REPLY,
        ETHTOOL_MSG_MM_NTF,
+       ETHTOOL_MSG_TS_GET_REPLY,
 
        /* add new constants above here */
        __ETHTOOL_MSG_KERNEL_CNT,
@@ -975,6 +977,18 @@ enum {
        ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
 };
 
+/* TS LAYER */
+
+enum {
+       ETHTOOL_A_TS_UNSPEC,
+       ETHTOOL_A_TS_HEADER,                    /* nest - _A_HEADER_* */
+       ETHTOOL_A_TS_LAYER,                     /* u32 */
+
+       /* add new constants above here */
+       __ETHTOOL_A_TS_CNT,
+       ETHTOOL_A_TS_MAX = (__ETHTOOL_A_TS_CNT - 1)
+};
+
 /* generic netlink info */
 #define ETHTOOL_GENL_NAME "ethtool"
 #define ETHTOOL_GENL_VERSION 1
index df8091998c8dc35c67bd1ac07ad74cba783055fb..4551fb3d77206be4dca3b7599ec5637c64428659 100644 (file)
 #include <linux/types.h>
 #include <linux/socket.h>   /* for SO_TIMESTAMPING */
 
+/* Layer of the TIMESTAMPING provider */
+enum timestamping_layer {
+       NO_TIMESTAMPING,
+       SOFTWARE_TIMESTAMPING,
+       MAC_TIMESTAMPING,
+       PHY_TIMESTAMPING,
+
+       __TIMESTAMPING_COUNT,
+};
+
 /* SO_TIMESTAMPING flags */
 enum {
        SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
index 504f954a1b2842a63a2baca0dd22c0b785f4351b..4ea64c080639fd1d077dd89ac53a8fd1c8f72050 100644 (file)
@@ -8,4 +8,4 @@ ethtool_nl-y    := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
                   linkstate.o debug.o wol.o features.o privflags.o rings.o \
                   channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
                   tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
-                  module.o pse-pd.o plca.o mm.o
+                  module.o pse-pd.o plca.o mm.o ts.o
index 28b8aaaf9bcb3c5dcfc10be9d0d9cab1b6e5c4e1..a264b635f7d38bc18e325bfc125656b78ce46c35 100644 (file)
@@ -35,6 +35,7 @@ extern const char wol_mode_names[][ETH_GSTRING_LEN];
 extern const char sof_timestamping_names[][ETH_GSTRING_LEN];
 extern const char ts_tx_type_names[][ETH_GSTRING_LEN];
 extern const char ts_rx_filter_names[][ETH_GSTRING_LEN];
+extern const char ts_layer_names[][ETH_GSTRING_LEN];
 extern const char udp_tunnel_type_names[][ETH_GSTRING_LEN];
 
 int __ethtool_get_link(struct net_device *dev);
index 3bbd5afb7b31cf000f3e4e6ade6542c39456b9e9..561c0931d055c9a926e8c6e3152b50a11de14571 100644 (file)
@@ -306,6 +306,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
        [ETHTOOL_MSG_PLCA_GET_STATUS]   = &ethnl_plca_status_request_ops,
        [ETHTOOL_MSG_MM_GET]            = &ethnl_mm_request_ops,
        [ETHTOOL_MSG_MM_SET]            = &ethnl_mm_request_ops,
+       [ETHTOOL_MSG_TS_GET]            = &ethnl_ts_request_ops,
 };
 
 static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@@ -1128,6 +1129,15 @@ static const struct genl_ops ethtool_genl_ops[] = {
                .policy = ethnl_mm_set_policy,
                .maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1,
        },
+       {
+               .cmd    = ETHTOOL_MSG_TS_GET,
+               .doit   = ethnl_default_doit,
+               .start  = ethnl_default_start,
+               .dumpit = ethnl_default_dumpit,
+               .done   = ethnl_default_done,
+               .policy = ethnl_ts_get_policy,
+               .maxattr = ARRAY_SIZE(ethnl_ts_get_policy) - 1,
+       },
 };
 
 static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
index 9a333a8d04c1f0d83c14e8983e4ca01578cb26f7..1e6085198accafde362f9026068ebc97d151533d 100644 (file)
@@ -395,6 +395,7 @@ extern const struct ethnl_request_ops ethnl_rss_request_ops;
 extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
 extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
 extern const struct ethnl_request_ops ethnl_mm_request_ops;
+extern const struct ethnl_request_ops ethnl_ts_request_ops;
 
 extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
 extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
@@ -441,6 +442,7 @@ extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]
 extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];
 extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1];
 extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
+extern const struct nla_policy ethnl_ts_get_policy[ETHTOOL_A_TS_HEADER + 1];
 
 int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
diff --git a/net/ethtool/ts.c b/net/ethtool/ts.c
new file mode 100644 (file)
index 0000000..066cb06
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/net_tstamp.h>
+#include <linux/phy.h>
+
+#include "netlink.h"
+#include "common.h"
+#include "bitset.h"
+
+struct ts_req_info {
+       struct ethnl_req_info           base;
+};
+
+struct ts_reply_data {
+       struct ethnl_reply_data         base;
+       enum timestamping_layer         ts_layer;
+};
+
+#define TS_REPDATA(__reply_base) \
+       container_of(__reply_base, struct ts_reply_data, base)
+
+/* TS_GET */
+const struct nla_policy ethnl_ts_get_policy[] = {
+       [ETHTOOL_A_TS_HEADER]           =
+               NLA_POLICY_NESTED(ethnl_header_policy),
+};
+
+static int ts_prepare_data(const struct ethnl_req_info *req_base,
+                          struct ethnl_reply_data *reply_base,
+                          const struct genl_info *info)
+{
+       struct ts_reply_data *data = TS_REPDATA(reply_base);
+       struct net_device *dev = reply_base->dev;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       int ret;
+
+       ret = ethnl_ops_begin(dev);
+       if (ret < 0)
+               return ret;
+
+       if (phy_has_tsinfo(dev->phydev)) {
+               data->ts_layer = PHY_TIMESTAMPING;
+       } else if (ops->get_ts_info) {
+               struct ethtool_ts_info ts_info = {0};
+
+               ops->get_ts_info(dev, &ts_info);
+               if (ts_info.so_timestamping &
+                   SOF_TIMESTAMPING_HARDWARE_MASK)
+                       data->ts_layer = MAC_TIMESTAMPING;
+
+               if (ts_info.so_timestamping &
+                   SOF_TIMESTAMPING_SOFTWARE_MASK)
+                       data->ts_layer = SOFTWARE_TIMESTAMPING;
+       } else {
+               data->ts_layer = NO_TIMESTAMPING;
+       }
+
+       ethnl_ops_complete(dev);
+
+       return ret;
+}
+
+static int ts_reply_size(const struct ethnl_req_info *req_base,
+                        const struct ethnl_reply_data *reply_base)
+{
+       return nla_total_size(sizeof(u32));
+}
+
+static int ts_fill_reply(struct sk_buff *skb,
+                        const struct ethnl_req_info *req_base,
+                        const struct ethnl_reply_data *reply_base)
+{
+       struct ts_reply_data *data = TS_REPDATA(reply_base);
+
+       return nla_put_u32(skb, ETHTOOL_A_TS_LAYER, data->ts_layer);
+}
+
+const struct ethnl_request_ops ethnl_ts_request_ops = {
+       .request_cmd            = ETHTOOL_MSG_TS_GET,
+       .reply_cmd              = ETHTOOL_MSG_TS_GET_REPLY,
+       .hdr_attr               = ETHTOOL_A_TS_HEADER,
+       .req_info_size          = sizeof(struct ts_req_info),
+       .reply_data_size        = sizeof(struct ts_reply_data),
+
+       .prepare_data           = ts_prepare_data,
+       .reply_size             = ts_reply_size,
+       .fill_reply             = ts_fill_reply,
+};