ethtool: add a new command for getting PHC virtual clocks

Add an interface for getting PHC (PTP Hardware Clock)
virtual clocks, which are based on PHC physical clock
providing hardware timestamp to network packets.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Yangbo Lu 2021-06-30 16:11:56 +08:00 committed by David S. Miller
parent acb288e804
commit c156174a67
8 changed files with 167 additions and 1 deletions

View File

@ -212,6 +212,7 @@ Userspace to kernel:
``ETHTOOL_MSG_FEC_SET`` set FEC settings
``ETHTOOL_MSG_MODULE_EEPROM_GET`` read SFP module EEPROM
``ETHTOOL_MSG_STATS_GET`` get standard statistics
``ETHTOOL_MSG_PHC_VCLOCKS_GET`` get PHC virtual clocks info
===================================== ================================
Kernel to userspace:
@ -250,6 +251,7 @@ Kernel to userspace:
``ETHTOOL_MSG_FEC_NTF`` FEC settings
``ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY`` read SFP module EEPROM
``ETHTOOL_MSG_STATS_GET_REPLY`` standard statistics
``ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY`` PHC virtual clocks info
======================================== =================================
``GET`` requests are sent by userspace applications to retrieve device
@ -1477,6 +1479,25 @@ Low and high bounds are inclusive, for example:
etherStatsPkts512to1023Octets 512 1023
============================= ==== ====
PHC_VCLOCKS_GET
===============
Query device PHC virtual clocks information.
Request contents:
==================================== ====== ==========================
``ETHTOOL_A_PHC_VCLOCKS_HEADER`` nested request header
==================================== ====== ==========================
Kernel response contents:
==================================== ====== ==========================
``ETHTOOL_A_PHC_VCLOCKS_HEADER`` nested reply header
``ETHTOOL_A_PHC_VCLOCKS_NUM`` u32 PHC virtual clocks number
``ETHTOOL_A_PHC_VCLOCKS_INDEX`` s32 PHC index array
==================================== ====== ==========================
Request translation
===================
@ -1575,4 +1596,5 @@ are netlink only.
n/a ``ETHTOOL_MSG_CABLE_TEST_ACT``
n/a ``ETHTOOL_MSG_CABLE_TEST_TDR_ACT``
n/a ``ETHTOOL_MSG_TUNNEL_INFO_GET``
n/a ``ETHTOOL_MSG_PHC_VCLOCKS_GET``
=================================== =====================================

View File

@ -757,6 +757,16 @@ void
ethtool_params_from_link_mode(struct ethtool_link_ksettings *link_ksettings,
enum ethtool_link_mode_bit_indices link_mode);
/**
* ethtool_get_phc_vclocks - Derive phc vclocks information, and caller
* is responsible to free memory of vclock_index
* @dev: pointer to net_device structure
* @vclock_index: pointer to pointer of vclock index
*
* Return number of phc vclocks
*/
int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index);
/**
* ethtool_sprintf - Write formatted string to ethtool string data
* @data: Pointer to start of string to update

View File

@ -46,6 +46,7 @@ enum {
ETHTOOL_MSG_FEC_SET,
ETHTOOL_MSG_MODULE_EEPROM_GET,
ETHTOOL_MSG_STATS_GET,
ETHTOOL_MSG_PHC_VCLOCKS_GET,
/* add new constants above here */
__ETHTOOL_MSG_USER_CNT,
@ -88,6 +89,7 @@ enum {
ETHTOOL_MSG_FEC_NTF,
ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY,
ETHTOOL_MSG_STATS_GET_REPLY,
ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY,
/* add new constants above here */
__ETHTOOL_MSG_KERNEL_CNT,
@ -440,6 +442,19 @@ enum {
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
};
/* PHC VCLOCKS */
enum {
ETHTOOL_A_PHC_VCLOCKS_UNSPEC,
ETHTOOL_A_PHC_VCLOCKS_HEADER, /* nest - _A_HEADER_* */
ETHTOOL_A_PHC_VCLOCKS_NUM, /* u32 */
ETHTOOL_A_PHC_VCLOCKS_INDEX, /* array, s32 */
/* add new constants above here */
__ETHTOOL_A_PHC_VCLOCKS_CNT,
ETHTOOL_A_PHC_VCLOCKS_MAX = (__ETHTOOL_A_PHC_VCLOCKS_CNT - 1)
};
/* CABLE TEST */
enum {

View File

@ -7,4 +7,4 @@ obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.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
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o

View File

@ -4,6 +4,7 @@
#include <linux/net_tstamp.h>
#include <linux/phy.h>
#include <linux/rtnetlink.h>
#include <linux/ptp_clock_kernel.h>
#include "common.h"
@ -554,6 +555,18 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
return 0;
}
int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index)
{
struct ethtool_ts_info info = { };
int num = 0;
if (!__ethtool_get_ts_info(dev, &info))
num = ptp_get_vclocks_index(info.phc_index, vclock_index);
return num;
}
EXPORT_SYMBOL(ethtool_get_phc_vclocks);
const struct ethtool_phy_ops *ethtool_phy_ops;
void ethtool_set_ethtool_phy_ops(const struct ethtool_phy_ops *ops)

View File

@ -248,6 +248,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
[ETHTOOL_MSG_TSINFO_GET] = &ethnl_tsinfo_request_ops,
[ETHTOOL_MSG_MODULE_EEPROM_GET] = &ethnl_module_eeprom_request_ops,
[ETHTOOL_MSG_STATS_GET] = &ethnl_stats_request_ops,
[ETHTOOL_MSG_PHC_VCLOCKS_GET] = &ethnl_phc_vclocks_request_ops,
};
static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
@ -958,6 +959,15 @@ static const struct genl_ops ethtool_genl_ops[] = {
.policy = ethnl_stats_get_policy,
.maxattr = ARRAY_SIZE(ethnl_stats_get_policy) - 1,
},
{
.cmd = ETHTOOL_MSG_PHC_VCLOCKS_GET,
.doit = ethnl_default_doit,
.start = ethnl_default_start,
.dumpit = ethnl_default_dumpit,
.done = ethnl_default_done,
.policy = ethnl_phc_vclocks_get_policy,
.maxattr = ARRAY_SIZE(ethnl_phc_vclocks_get_policy) - 1,
},
};
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {

View File

@ -347,6 +347,7 @@ extern const struct ethnl_request_ops ethnl_tsinfo_request_ops;
extern const struct ethnl_request_ops ethnl_fec_request_ops;
extern const struct ethnl_request_ops ethnl_module_eeprom_request_ops;
extern const struct ethnl_request_ops ethnl_stats_request_ops;
extern const struct ethnl_request_ops ethnl_phc_vclocks_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];
@ -382,6 +383,7 @@ extern const struct nla_policy ethnl_fec_get_policy[ETHTOOL_A_FEC_HEADER + 1];
extern const struct nla_policy ethnl_fec_set_policy[ETHTOOL_A_FEC_AUTO + 1];
extern const struct nla_policy ethnl_module_eeprom_get_policy[ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS + 1];
extern const struct nla_policy ethnl_stats_get_policy[ETHTOOL_A_STATS_GROUPS + 1];
extern const struct nla_policy ethnl_phc_vclocks_get_policy[ETHTOOL_A_PHC_VCLOCKS_HEADER + 1];
int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);

94
net/ethtool/phc_vclocks.c Normal file
View File

@ -0,0 +1,94 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2021 NXP
*/
#include "netlink.h"
#include "common.h"
struct phc_vclocks_req_info {
struct ethnl_req_info base;
};
struct phc_vclocks_reply_data {
struct ethnl_reply_data base;
int num;
int *index;
};
#define PHC_VCLOCKS_REPDATA(__reply_base) \
container_of(__reply_base, struct phc_vclocks_reply_data, base)
const struct nla_policy ethnl_phc_vclocks_get_policy[] = {
[ETHTOOL_A_PHC_VCLOCKS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
};
static int phc_vclocks_prepare_data(const struct ethnl_req_info *req_base,
struct ethnl_reply_data *reply_base,
struct genl_info *info)
{
struct phc_vclocks_reply_data *data = PHC_VCLOCKS_REPDATA(reply_base);
struct net_device *dev = reply_base->dev;
int ret;
ret = ethnl_ops_begin(dev);
if (ret < 0)
return ret;
data->num = ethtool_get_phc_vclocks(dev, &data->index);
ethnl_ops_complete(dev);
return ret;
}
static int phc_vclocks_reply_size(const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
{
const struct phc_vclocks_reply_data *data =
PHC_VCLOCKS_REPDATA(reply_base);
int len = 0;
if (data->num > 0) {
len += nla_total_size(sizeof(u32));
len += nla_total_size(sizeof(s32) * data->num);
}
return len;
}
static int phc_vclocks_fill_reply(struct sk_buff *skb,
const struct ethnl_req_info *req_base,
const struct ethnl_reply_data *reply_base)
{
const struct phc_vclocks_reply_data *data =
PHC_VCLOCKS_REPDATA(reply_base);
if (data->num <= 0)
return 0;
if (nla_put_u32(skb, ETHTOOL_A_PHC_VCLOCKS_NUM, data->num) ||
nla_put(skb, ETHTOOL_A_PHC_VCLOCKS_INDEX,
sizeof(s32) * data->num, data->index))
return -EMSGSIZE;
return 0;
}
static void phc_vclocks_cleanup_data(struct ethnl_reply_data *reply_base)
{
const struct phc_vclocks_reply_data *data =
PHC_VCLOCKS_REPDATA(reply_base);
kfree(data->index);
}
const struct ethnl_request_ops ethnl_phc_vclocks_request_ops = {
.request_cmd = ETHTOOL_MSG_PHC_VCLOCKS_GET,
.reply_cmd = ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY,
.hdr_attr = ETHTOOL_A_PHC_VCLOCKS_HEADER,
.req_info_size = sizeof(struct phc_vclocks_req_info),
.reply_data_size = sizeof(struct phc_vclocks_reply_data),
.prepare_data = phc_vclocks_prepare_data,
.reply_size = phc_vclocks_reply_size,
.fill_reply = phc_vclocks_fill_reply,
.cleanup_data = phc_vclocks_cleanup_data,
};