Skip to content

Commit

Permalink
ethtool: add a new command for getting PHC virtual clocks
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
yangbolu1991 authored and davem330 committed Jul 1, 2021
1 parent acb288e commit c156174
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 1 deletion.
22 changes: 22 additions & 0 deletions Documentation/networking/ethtool-netlink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
===================

Expand Down Expand Up @@ -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``
=================================== =====================================
10 changes: 10 additions & 0 deletions include/linux/ethtool.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions include/uapi/linux/ethtool_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion net/ethtool/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 13 additions & 0 deletions net/ethtool/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions net/ethtool/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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[] = {
Expand Down
2 changes: 2 additions & 0 deletions net/ethtool/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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);
Expand Down
94 changes: 94 additions & 0 deletions net/ethtool/phc_vclocks.c
Original file line number Diff line number Diff line change
@@ -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,
};

0 comments on commit c156174

Please sign in to comment.