mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
net: ethtool: Add a command to expose current time stamping layer
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>
This commit is contained in:
committed by
David S. Miller
parent
acec05fb78
commit
11d55be06d
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -306,6 +306,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
|
||||
[ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops,
|
||||
[ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops,
|
||||
[ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops,
|
||||
[ETHTOOL_MSG_TS_GET] = ðnl_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[] = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
88
net/ethtool/ts.c
Normal file
88
net/ethtool/ts.c
Normal file
@@ -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,
|
||||
};
|
||||
Reference in New Issue
Block a user