Skip to content

Commit

Permalink
net: ethtool: tsinfo: Enhance tsinfo to support several hwtstamp by n…
Browse files Browse the repository at this point in the history
…et topology

Either the MAC or the PHY can provide hwtstamp, so we should be able to
read the tsinfo for any hwtstamp provider.

Enhance 'get' command to retrieve tsinfo of hwtstamp providers within a
network topology.

Add support for a specific dump command to retrieve all hwtstamp
providers within the network topology, with added functionality for
filtered dump to target a single interface.

Signed-off-by: Kory Maincent <kory.maincent@bootlin.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Kory Maincent authored and David S. Miller committed Dec 16, 2024
1 parent 35f7cad commit b9e3f7d
Show file tree
Hide file tree
Showing 10 changed files with 563 additions and 21 deletions.
20 changes: 20 additions & 0 deletions Documentation/netlink/specs/ethtool.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,20 @@ attribute-sets:
-
name: tx-err
type: uint
-
name: ts-hwtstamp-provider
attr-cnt-name: __ethtool-a-ts-hwtstamp-provider-cnt
attributes:
-
name: unspec
type: unused
value: 0
-
name: index
type: u32
-
name: qualifier
type: u32
-
name: tsinfo
attr-cnt-name: __ethtool-a-tsinfo-cnt
Expand Down Expand Up @@ -867,6 +881,10 @@ attribute-sets:
name: stats
type: nest
nested-attributes: ts-stat
-
name: hwtstamp-provider
type: nest
nested-attributes: ts-hwtstamp-provider
-
name: cable-result
attr-cnt-name: __ethtool-a-cable-result-cnt
Expand Down Expand Up @@ -1912,6 +1930,7 @@ operations:
request:
attributes:
- header
- hwtstamp-provider
reply:
attributes:
- header
Expand All @@ -1920,6 +1939,7 @@ operations:
- rx-filters
- phc-index
- stats
- hwtstamp-provider
dump: *tsinfo-get-op
-
name: cable-test-act
Expand Down
7 changes: 4 additions & 3 deletions Documentation/networking/ethtool-netlink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1245,9 +1245,10 @@ Gets timestamping information like ``ETHTOOL_GET_TS_INFO`` ioctl request.

Request contents:

===================================== ====== ==========================
``ETHTOOL_A_TSINFO_HEADER`` nested request header
===================================== ====== ==========================
======================================== ====== ============================
``ETHTOOL_A_TSINFO_HEADER`` nested request header
``ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER`` nested PTP hw clock provider
======================================== ====== ============================

Kernel response contents:

Expand Down
4 changes: 4 additions & 0 deletions include/linux/ethtool.h
Original file line number Diff line number Diff line change
Expand Up @@ -711,13 +711,15 @@ struct ethtool_rxfh_param {
* @cmd: command number = %ETHTOOL_GET_TS_INFO
* @so_timestamping: bit mask of the sum of the supported SO_TIMESTAMPING flags
* @phc_index: device index of the associated PHC, or -1 if there is none
* @phc_qualifier: qualifier of the associated PHC
* @tx_types: bit mask of the supported hwtstamp_tx_types enumeration values
* @rx_filters: bit mask of the supported hwtstamp_rx_filters enumeration values
*/
struct kernel_ethtool_ts_info {
u32 cmd;
u32 so_timestamping;
int phc_index;
enum hwtstamp_provider_qualifier phc_qualifier;
enum hwtstamp_tx_types tx_types;
enum hwtstamp_rx_filters rx_filters;
};
Expand Down Expand Up @@ -749,6 +751,7 @@ struct kernel_ethtool_ts_info {
* @rss_context argument to @create_rxfh_context and friends.
* @supported_coalesce_params: supported types of interrupt coalescing.
* @supported_ring_params: supported ring params.
* @supported_hwtstamp_qualifiers: bitfield of supported hwtstamp qualifier.
* @get_drvinfo: Report driver/device information. Modern drivers no
* longer have to implement this callback. Most fields are
* correctly filled in by the core using system information, or
Expand Down Expand Up @@ -966,6 +969,7 @@ struct ethtool_ops {
u32 rxfh_max_num_contexts;
u32 supported_coalesce_params;
u32 supported_ring_params;
u32 supported_hwtstamp_qualifiers;
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
int (*get_regs_len)(struct net_device *);
void (*get_regs)(struct net_device *, struct ethtool_regs *, void *);
Expand Down
10 changes: 10 additions & 0 deletions include/uapi/linux/ethtool_netlink_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,15 @@ enum {
ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)
};

enum {
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_UNSPEC,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,

__ETHTOOL_A_TS_HWTSTAMP_PROVIDER_CNT,
ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX = (__ETHTOOL_A_TS_HWTSTAMP_PROVIDER_CNT - 1)
};

enum {
ETHTOOL_A_TSINFO_UNSPEC,
ETHTOOL_A_TSINFO_HEADER,
Expand All @@ -393,6 +402,7 @@ enum {
ETHTOOL_A_TSINFO_RX_FILTERS,
ETHTOOL_A_TSINFO_PHC_INDEX,
ETHTOOL_A_TSINFO_STATS,
ETHTOOL_A_TSINFO_HWTSTAMP_PROVIDER,

__ETHTOOL_A_TSINFO_CNT,
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
Expand Down
141 changes: 132 additions & 9 deletions net/ethtool/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
#include <linux/phy.h>
#include <linux/rtnetlink.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/phy_link_topology.h>

#include "netlink.h"
#include "common.h"
#include "../core/dev.h"


const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
[NETIF_F_SG_BIT] = "tx-scatter-gather",
Expand Down Expand Up @@ -763,27 +766,147 @@ int ethtool_check_ops(const struct ethtool_ops *ops)
return 0;
}

int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info)
static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
struct phy_device *phydev = dev->phydev;
int err = 0;

memset(info, 0, sizeof(*info));
info->cmd = ETHTOOL_GET_TS_INFO;
info->phc_index = -1;
}

int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc)
{
const struct ethtool_ops *ops = dev->ethtool_ops;
int err;

if (!ops->get_ts_info)
return -ENODEV;

/* Does ptp comes from netdev */
ethtool_init_tsinfo(info);
info->phc_qualifier = hwprov_desc->qualifier;
err = ops->get_ts_info(dev, info);
if (err)
return err;

if (info->phc_index == hwprov_desc->index &&
net_support_hwtstamp_qualifier(dev, hwprov_desc->qualifier))
return 0;

return -ENODEV;
}

int
ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc)
{
int err;

/* Only precise qualifier is supported in phydev */
if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
return -ENODEV;

/* Look in the phy topology */
if (dev->link_topo) {
struct phy_device_node *pdn;
unsigned long phy_index;

xa_for_each(&dev->link_topo->phys, phy_index, pdn) {
if (!phy_has_tsinfo(pdn->phy))
continue;

ethtool_init_tsinfo(info);
err = phy_ts_info(pdn->phy, info);
if (err)
return err;

if (info->phc_index == hwprov_desc->index)
return 0;
}
return -ENODEV;
}

/* Look on the dev->phydev */
if (phy_has_tsinfo(dev->phydev)) {
ethtool_init_tsinfo(info);
err = phy_ts_info(dev->phydev, info);
if (err)
return err;

if (info->phc_index == hwprov_desc->index)
return 0;
}

return -ENODEV;
}

int ethtool_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc)
{
int err;

if (phy_is_default_hwtstamp(phydev) && phy_has_tsinfo(phydev))
err = phy_ts_info(phydev, info);
else if (ops->get_ts_info)
err = ops->get_ts_info(dev, info);
err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc);
if (err == -ENODEV)
err = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc);

info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE;

return err;
}

int __ethtool_get_ts_info(struct net_device *dev,
struct kernel_ethtool_ts_info *info)
{
struct hwtstamp_provider *hwprov;

hwprov = rtnl_dereference(dev->hwprov);
/* No provider specified, use default behavior */
if (!hwprov) {
const struct ethtool_ops *ops = dev->ethtool_ops;
struct phy_device *phydev = dev->phydev;
int err = 0;

ethtool_init_tsinfo(info);
if (phy_is_default_hwtstamp(phydev) &&
phy_has_tsinfo(phydev))
err = phy_ts_info(phydev, info);
else if (ops->get_ts_info)
err = ops->get_ts_info(dev, info);

info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE;

return err;
}

return ethtool_get_ts_info_by_phc(dev, info, &hwprov->desc);
}

bool net_support_hwtstamp_qualifier(struct net_device *dev,
enum hwtstamp_provider_qualifier qualifier)
{
const struct ethtool_ops *ops = dev->ethtool_ops;

if (!ops)
return false;

/* Return true with precise qualifier and with NIC without
* qualifier description to not break the old behavior.
*/
if (!ops->supported_hwtstamp_qualifiers &&
qualifier == HWTSTAMP_PROVIDER_QUALIFIER_PRECISE)
return true;

if (ops->supported_hwtstamp_qualifiers & BIT(qualifier))
return true;

return false;
}

int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index)
{
struct kernel_ethtool_ts_info info = { };
Expand Down
13 changes: 13 additions & 0 deletions net/ethtool/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct link_mode_info {
};

struct genl_info;
struct hwtstamp_provider_desc;

extern const char
netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
Expand Down Expand Up @@ -49,6 +50,18 @@ int ethtool_check_max_channel(struct net_device *dev,
struct genl_info *info);
int ethtool_check_rss_ctx_busy(struct net_device *dev, u32 rss_context);
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info);
int ethtool_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc);
int ethtool_net_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc);
int
ethtool_phy_get_ts_info_by_phc(struct net_device *dev,
struct kernel_ethtool_ts_info *info,
struct hwtstamp_provider_desc *hwprov_desc);
bool net_support_hwtstamp_qualifier(struct net_device *dev,
enum hwtstamp_provider_qualifier qualifier);

extern const struct ethtool_phy_ops *ethtool_phy_ops;
extern const struct ethtool_pse_ops *ethtool_pse_ops;
Expand Down
6 changes: 3 additions & 3 deletions net/ethtool/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,9 +1074,9 @@ static const struct genl_ops ethtool_genl_ops[] = {
{
.cmd = ETHTOOL_MSG_TSINFO_GET,
.doit = ethnl_default_doit,
.start = ethnl_default_start,
.dumpit = ethnl_default_dumpit,
.done = ethnl_default_done,
.start = ethnl_tsinfo_start,
.dumpit = ethnl_tsinfo_dumpit,
.done = ethnl_tsinfo_done,
.policy = ethnl_tsinfo_get_policy,
.maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1,
},
Expand Down
5 changes: 4 additions & 1 deletion net/ethtool/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ extern const struct nla_policy ethnl_pause_get_policy[ETHTOOL_A_PAUSE_STATS_SRC
extern const struct nla_policy ethnl_pause_set_policy[ETHTOOL_A_PAUSE_TX + 1];
extern const struct nla_policy ethnl_eee_get_policy[ETHTOOL_A_EEE_HEADER + 1];
extern const struct nla_policy ethnl_eee_set_policy[ETHTOOL_A_EEE_TX_LPI_TIMER + 1];
extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_HEADER + 1];
extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1];
extern const struct nla_policy ethnl_cable_test_act_policy[ETHTOOL_A_CABLE_TEST_HEADER + 1];
extern const struct nla_policy ethnl_cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG + 1];
extern const struct nla_policy ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_HEADER + 1];
Expand Down Expand Up @@ -499,6 +499,9 @@ int ethnl_phy_start(struct netlink_callback *cb);
int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info);
int ethnl_phy_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
int ethnl_phy_done(struct netlink_callback *cb);
int ethnl_tsinfo_start(struct netlink_callback *cb);
int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
int ethnl_tsinfo_done(struct netlink_callback *cb);

extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
Expand Down
20 changes: 20 additions & 0 deletions net/ethtool/ts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef _NET_ETHTOOL_TS_H
#define _NET_ETHTOOL_TS_H

#include "netlink.h"

static const struct nla_policy
ethnl_ts_hwtst_prov_policy[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX + 1] = {
[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX] = { .type = NLA_U32 },
[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER] =
NLA_POLICY_MAX(NLA_U32, HWTSTAMP_PROVIDER_QUALIFIER_CNT - 1)
};

int ts_parse_hwtst_provider(const struct nlattr *nest,
struct hwtstamp_provider_desc *hwprov_desc,
struct netlink_ext_ack *extack,
bool *mod);

#endif /* _NET_ETHTOOL_TS_H */
Loading

0 comments on commit b9e3f7d

Please sign in to comment.