Commit 0e9c1277 authored by Rahul Rameshbabu's avatar Rahul Rameshbabu Committed by Jakub Kicinski
Browse files

ethtool: add interface to read Tx hardware timestamping statistics



Multiple network devices that support hardware timestamping appear to have
common behavior with regards to timestamp handling. Implement common Tx
hardware timestamping statistics in a tx_stats struct_group. Common Rx
hardware timestamping statistics can subsequently be implemented in a
rx_stats struct_group for ethtool_ts_stats.

Signed-off-by: default avatarRahul Rameshbabu <rrameshbabu@nvidia.com>
Reviewed-by: default avatarDragos Tatulea <dtatulea@nvidia.com>
Link: https://lore.kernel.org/r/20240403212931.128541-2-rrameshbabu@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 4196aee0
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -565,6 +565,18 @@ attribute-sets:
      -
        name: tx-lpi-timer
        type: u32
  -
    name: ts-stat
    attributes:
      -
        name: tx-pkts
        type: uint
      -
        name: tx-lost
        type: uint
      -
        name: tx-err
        type: uint
  -
    name: tsinfo
    attributes:
@@ -587,6 +599,10 @@ attribute-sets:
      -
        name: phc-index
        type: u32
      -
        name: stats
        type: nest
        nested-attributes: ts-stat
  -
    name: cable-result
    attributes:
@@ -1394,6 +1410,7 @@ operations:
            - tx-types
            - rx-filters
            - phc-index
            - stats
      dump: *tsinfo-get-op
    -
      name: cable-test-act
+9 −0
Original line number Diff line number Diff line
@@ -1237,12 +1237,21 @@ Kernel response contents:
  ``ETHTOOL_A_TSINFO_TX_TYPES``          bitset  supported Tx types
  ``ETHTOOL_A_TSINFO_RX_FILTERS``        bitset  supported Rx filters
  ``ETHTOOL_A_TSINFO_PHC_INDEX``         u32     PTP hw clock index
  ``ETHTOOL_A_TSINFO_STATS``             nested  HW timestamping statistics
  =====================================  ======  ==========================

``ETHTOOL_A_TSINFO_PHC_INDEX`` is absent if there is no associated PHC (there
is no special value for this case). The bitset attributes are omitted if they
would be empty (no bit set).

Additional hardware timestamping statistics response contents:

  =====================================  ======  ===================================
  ``ETHTOOL_A_TS_STAT_TX_PKTS``          u64     Packets with Tx HW timestamps
  ``ETHTOOL_A_TS_STAT_TX_LOST``          u64     Tx HW timestamp not arrived count
  ``ETHTOOL_A_TS_STAT_TX_ERR``           u64     HW error request Tx timestamp count
  =====================================  ======  ===================================

CABLE_TEST
==========

+26 −1
Original line number Diff line number Diff line
@@ -480,6 +480,26 @@ struct ethtool_rmon_stats {
	);
};

/**
 * struct ethtool_ts_stats - HW timestamping statistics
 * @pkts: Number of packets successfully timestamped by the hardware.
 * @lost: Number of hardware timestamping requests where the timestamping
 *	information from the hardware never arrived for submission with
 *	the skb.
 * @err: Number of arbitrary timestamp generation error events that the
 *	hardware encountered, exclusive of @lost statistics. Cases such
 *	as resource exhaustion, unavailability, firmware errors, and
 *	detected illogical timestamp values not submitted with the skb
 *	are inclusive to this counter.
 */
struct ethtool_ts_stats {
	struct_group(tx_stats,
		u64 pkts;
		u64 lost;
		u64 err;
	);
};

#define ETH_MODULE_EEPROM_PAGE_LEN	128
#define ETH_MODULE_MAX_I2C_ADDRESS	0x7f

@@ -755,7 +775,10 @@ struct ethtool_rxfh_param {
 * @get_ts_info: Get the time stamping and PTP hardware clock capabilities.
 *	It may be called with RCU, or rtnl or reference on the device.
 *	Drivers supporting transmit time stamps in software should set this to
 *	ethtool_op_get_ts_info().
 *	ethtool_op_get_ts_info(). Drivers must not zero statistics which they
 *	don't report. The stats	structure is initialized to ETHTOOL_STAT_NOT_SET
 *	indicating driver does not report statistics.
 * @get_ts_stats: Query the device hardware timestamping statistics.
 * @get_module_info: Get the size and type of the eeprom contained within
 *	a plug-in module.
 * @get_module_eeprom: Get the eeprom information from the plug-in module
@@ -898,6 +921,8 @@ struct ethtool_ops {
				 struct ethtool_dump *, void *);
	int	(*set_dump)(struct net_device *, struct ethtool_dump *);
	int	(*get_ts_info)(struct net_device *, struct ethtool_ts_info *);
	void	(*get_ts_stats)(struct net_device *dev,
				struct ethtool_ts_stats *ts_stats);
	int     (*get_module_info)(struct net_device *,
				   struct ethtool_modinfo *);
	int     (*get_module_eeprom)(struct net_device *,
+14 −0
Original line number Diff line number Diff line
@@ -478,12 +478,26 @@ enum {
	ETHTOOL_A_TSINFO_TX_TYPES,			/* bitset */
	ETHTOOL_A_TSINFO_RX_FILTERS,			/* bitset */
	ETHTOOL_A_TSINFO_PHC_INDEX,			/* u32 */
	ETHTOOL_A_TSINFO_STATS,				/* nest - _A_TSINFO_STAT */

	/* add new constants above here */
	__ETHTOOL_A_TSINFO_CNT,
	ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
};

enum {
	ETHTOOL_A_TS_STAT_UNSPEC,

	ETHTOOL_A_TS_STAT_TX_PKTS,			/* u64 */
	ETHTOOL_A_TS_STAT_TX_LOST,			/* u64 */
	ETHTOOL_A_TS_STAT_TX_ERR,			/* u64 */

	/* add new constants above here */
	__ETHTOOL_A_TS_STAT_CNT,
	ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)

};

/* PHC VCLOCKS */

enum {
+51 −1
Original line number Diff line number Diff line
@@ -13,14 +13,18 @@ struct tsinfo_req_info {
struct tsinfo_reply_data {
	struct ethnl_reply_data		base;
	struct ethtool_ts_info		ts_info;
	struct ethtool_ts_stats		stats;
};

#define TSINFO_REPDATA(__reply_base) \
	container_of(__reply_base, struct tsinfo_reply_data, base)

#define ETHTOOL_TS_STAT_CNT \
	(__ETHTOOL_A_TS_STAT_CNT - (ETHTOOL_A_TS_STAT_UNSPEC + 1))

const struct nla_policy ethnl_tsinfo_get_policy[] = {
	[ETHTOOL_A_TSINFO_HEADER]		=
		NLA_POLICY_NESTED(ethnl_header_policy),
		NLA_POLICY_NESTED(ethnl_header_policy_stats),
};

static int tsinfo_prepare_data(const struct ethnl_req_info *req_base,
@@ -34,6 +38,12 @@ static int tsinfo_prepare_data(const struct ethnl_req_info *req_base,
	ret = ethnl_ops_begin(dev);
	if (ret < 0)
		return ret;
	if (req_base->flags & ETHTOOL_FLAG_STATS &&
	    dev->ethtool_ops->get_ts_stats) {
		ethtool_stats_init((u64 *)&data->stats,
				   sizeof(data->stats) / sizeof(u64));
		dev->ethtool_ops->get_ts_stats(dev, &data->stats);
	}
	ret = __ethtool_get_ts_info(dev, &data->ts_info);
	ethnl_ops_complete(dev);

@@ -79,10 +89,47 @@ static int tsinfo_reply_size(const struct ethnl_req_info *req_base,
	}
	if (ts_info->phc_index >= 0)
		len += nla_total_size(sizeof(u32));	/* _TSINFO_PHC_INDEX */
	if (req_base->flags & ETHTOOL_FLAG_STATS)
		len += nla_total_size(0) + /* _TSINFO_STATS */
		       nla_total_size_64bit(sizeof(u64)) * ETHTOOL_TS_STAT_CNT;

	return len;
}

static int tsinfo_put_stat(struct sk_buff *skb, u64 val, u16 attrtype)
{
	if (val == ETHTOOL_STAT_NOT_SET)
		return 0;
	if (nla_put_uint(skb, attrtype, val))
		return -EMSGSIZE;
	return 0;
}

static int tsinfo_put_stats(struct sk_buff *skb,
			    const struct ethtool_ts_stats *stats)
{
	struct nlattr *nest;

	nest = nla_nest_start(skb, ETHTOOL_A_TSINFO_STATS);
	if (!nest)
		return -EMSGSIZE;

	if (tsinfo_put_stat(skb, stats->tx_stats.pkts,
			    ETHTOOL_A_TS_STAT_TX_PKTS) ||
	    tsinfo_put_stat(skb, stats->tx_stats.lost,
			    ETHTOOL_A_TS_STAT_TX_LOST) ||
	    tsinfo_put_stat(skb, stats->tx_stats.err,
			    ETHTOOL_A_TS_STAT_TX_ERR))
		goto err_cancel;

	nla_nest_end(skb, nest);
	return 0;

err_cancel:
	nla_nest_cancel(skb, nest);
	return -EMSGSIZE;
}

static int tsinfo_fill_reply(struct sk_buff *skb,
			     const struct ethnl_req_info *req_base,
			     const struct ethnl_reply_data *reply_base)
@@ -119,6 +166,9 @@ static int tsinfo_fill_reply(struct sk_buff *skb,
	if (ts_info->phc_index >= 0 &&
	    nla_put_u32(skb, ETHTOOL_A_TSINFO_PHC_INDEX, ts_info->phc_index))
		return -EMSGSIZE;
	if (req_base->flags & ETHTOOL_FLAG_STATS &&
	    tsinfo_put_stats(skb, &data->stats))
		return -EMSGSIZE;

	return 0;
}