Commit 1c86514d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ethtool-stats'



Jakub Kicinski says:

====================
ethtool: add uAPI for reading standard stats

Continuing the effort of providing a unified access method
to standard stats, and explicitly tying the definitions to
the standards this series adds an API for general stats
which do no fit into more targeted control APIs.

There is nothing clever here, just a netlink API for dumping
statistics defined by standards and RFCs which today end up
in ethtool -S under infinite variations of names.

This series adds basic IEEE stats (for PHY, MAC, Ctrl frames)
and RMON stats. AFAICT other RFCs only duplicate the IEEE
stats.

This series does _not_ add a netlink API to read driver-defined
stats. There seems to be little to gain from moving that part
to netlink.

The netlink message format is very simple, and aims to allow
adding stats and groups with no changes to user tooling (which
IIUC is expected for ethtool).

On user space side we can re-use -S, and make it dump
standard stats if --groups are defined.

$ ethtool -S eth0 --groups eth-phy eth-mac eth-ctrl rmon
Stats for eth0:
eth-phy-SymbolErrorDuringCarrier: 0
eth-mac-FramesTransmittedOK: 0
eth-mac-FrameTooLongErrors: 0
eth-ctrl-MACControlFramesTransmitted: 0
eth-ctrl-MACControlFramesReceived: 1
eth-ctrl-UnsupportedOpcodesReceived: 0
rmon-etherStatsUndersizePkts: 0
rmon-etherStatsJabbers: 0
rmon-rx-etherStatsPkts64Octets: 1
rmon-rx-etherStatsPkts128to255Octets: 0
rmon-rx-etherStatsPkts1024toMaxOctets: 1
rmon-tx-etherStatsPkts64Octets: 1
rmon-tx-etherStatsPkts128to255Octets: 0
rmon-tx-etherStatsPkts1024toMaxOctets: 1

v1:

Driver support for mlxsw, mlx5 and bnxt included.

Compared to the RFC I went ahead with wrapping the stats into
a 1:1 nest. Now IDs of stats can start from 0, at a cost of
slightly "careful" u64 alignment handling.

v2:

Add missing kdoc in patch 5.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e5272ad4 b572ec9f
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ Userspace to kernel:
  ``ETHTOOL_MSG_TUNNEL_INFO_GET``       get tunnel offload info
  ``ETHTOOL_MSG_FEC_GET``               get FEC settings
  ``ETHTOOL_MSG_FEC_SET``               set FEC settings
  ``ETHTOOL_MSG_STATS_GET``             get standard statistics
  ===================================== ================================

Kernel to userspace:
@@ -246,6 +247,7 @@ Kernel to userspace:
  ``ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY`` tunnel offload info
  ``ETHTOOL_MSG_FEC_GET_REPLY``         FEC settings
  ``ETHTOOL_MSG_FEC_NTF``               FEC settings
  ``ETHTOOL_MSG_STATS_GET_REPLY``       standard statistics
  ===================================== =================================

``GET`` requests are sent by userspace applications to retrieve device
@@ -1391,6 +1393,86 @@ Kernel response contents:
``ETHTOOL_A_MODULE_EEPROM_DATA`` has an attribute length equal to the amount of
bytes driver actually read.

STATS_GET
=========

Get standard statistics for the interface. Note that this is not
a re-implementation of ``ETHTOOL_GSTATS`` which exposed driver-defined
stats.

Request contents:

  =======================================  ======  ==========================
  ``ETHTOOL_A_STATS_HEADER``               nested  request header
  ``ETHTOOL_A_STATS_GROUPS``               bitset  requested groups of stats
  =======================================  ======  ==========================

Kernel response contents:

 +-----------------------------------+--------+--------------------------------+
 | ``ETHTOOL_A_STATS_HEADER``        | nested | reply header                   |
 +-----------------------------------+--------+--------------------------------+
 | ``ETHTOOL_A_STATS_GRP``           | nested | one or more group of stats     |
 +-+---------------------------------+--------+--------------------------------+
 | | ``ETHTOOL_A_STATS_GRP_ID``      | u32    | group ID - ``ETHTOOL_STATS_*`` |
 +-+---------------------------------+--------+--------------------------------+
 | | ``ETHTOOL_A_STATS_GRP_SS_ID``   | u32    | string set ID for names        |
 +-+---------------------------------+--------+--------------------------------+
 | | ``ETHTOOL_A_STATS_GRP_STAT``    | nested | nest containing a statistic    |
 +-+---------------------------------+--------+--------------------------------+
 | | ``ETHTOOL_A_STATS_GRP_HIST_RX`` | nested | histogram statistic (Rx)       |
 +-+---------------------------------+--------+--------------------------------+
 | | ``ETHTOOL_A_STATS_GRP_HIST_TX`` | nested | histogram statistic (Tx)       |
 +-+---------------------------------+--------+--------------------------------+

Users specify which groups of statistics they are requesting via
the ``ETHTOOL_A_STATS_GROUPS`` bitset. Currently defined values are:

 ====================== ======== ===============================================
 ETHTOOL_STATS_ETH_MAC  eth-mac  Basic IEEE 802.3 MAC statistics (30.3.1.1.*)
 ETHTOOL_STATS_ETH_PHY  eth-phy  Basic IEEE 802.3 PHY statistics (30.3.2.1.*)
 ETHTOOL_STATS_ETH_CTRL eth-ctrl Basic IEEE 802.3 MAC Ctrl statistics (30.3.3.*)
 ETHTOOL_STATS_RMON     rmon     RMON (RFC 2819) statistics
 ====================== ======== ===============================================

Each group should have a corresponding ``ETHTOOL_A_STATS_GRP`` in the reply.
``ETHTOOL_A_STATS_GRP_ID`` identifies which group's statistics nest contains.
``ETHTOOL_A_STATS_GRP_SS_ID`` identifies the string set ID for the names of
the statistics in the group, if available.

Statistics are added to the ``ETHTOOL_A_STATS_GRP`` nest under
``ETHTOOL_A_STATS_GRP_STAT``. ``ETHTOOL_A_STATS_GRP_STAT`` should contain
single 8 byte (u64) attribute inside - the type of that attribute is
the statistic ID and the value is the value of the statistic.
Each group has its own interpretation of statistic IDs.
Attribute IDs correspond to strings from the string set identified
by ``ETHTOOL_A_STATS_GRP_SS_ID``. Complex statistics (such as RMON histogram
entries) are also listed inside ``ETHTOOL_A_STATS_GRP`` and do not have
a string defined in the string set.

RMON "histogram" counters count number of packets within given size range.
Because RFC does not specify the ranges beyond the standard 1518 MTU devices
differ in definition of buckets. For this reason the definition of packet ranges
is left to each driver.

``ETHTOOL_A_STATS_GRP_HIST_RX`` and ``ETHTOOL_A_STATS_GRP_HIST_TX`` nests
contain the following attributes:

 ================================= ====== ===================================
 ETHTOOL_A_STATS_RMON_HIST_BKT_LOW u32    low bound of the packet size bucket
 ETHTOOL_A_STATS_RMON_HIST_BKT_HI  u32    high bound of the bucket
 ETHTOOL_A_STATS_RMON_HIST_VAL     u64    packet counter
 ================================= ====== ===================================

Low and high bounds are inclusive, for example:

 ============================= ==== ====
 RFC statistic                 low  high
 ============================= ==== ====
 etherStatsPkts64Octets          0    64
 etherStatsPkts512to1023Octets 512  1023
 ============================= ==== ====

Request translation
===================

+42 −2
Original line number Diff line number Diff line
@@ -44,8 +44,27 @@ If `-s` is specified once the detailed errors won't be shown.
Protocol-specific statistics
----------------------------

Some of the interfaces used for configuring devices are also able
to report related statistics. For example ethtool interface used
Protocol-specific statistics are exposed via relevant interfaces,
the same interfaces as are used to configure them.

ethtool
~~~~~~~

Ethtool exposes common low-level statistics.
All the standard statistics are expected to be maintained
by the device, not the driver (as opposed to driver-defined stats
described in the next section which mix software and hardware stats).
For devices which contain unmanaged
switches (e.g. legacy SR-IOV or multi-host NICs) the events counted
may not pertain exclusively to the packets destined to
the local host interface. In other words the events may
be counted at the network port (MAC/PHY blocks) without separation
for different host side (PCIe) devices. Such ambiguity must not
be present when internal switch is managed by Linux (so called
switchdev mode for NICs).

Standard ethtool statistics can be accessed via the interfaces used
for configuration. For example ethtool interface used
to configure pause frames can report corresponding hardware counters::

  $ ethtool --include-statistics -a eth0
@@ -57,6 +76,27 @@ to configure pause frames can report corresponding hardware counters::
    tx_pause_frames: 1
    rx_pause_frames: 1

General Ethernet statistics not associated with any particular
functionality are exposed via ``ethtool -S $ifc`` by specifying
the ``--groups`` parameter::

  $ ethtool -S eth0 --groups eth-phy eth-mac eth-ctrl rmon
  Stats for eth0:
  eth-phy-SymbolErrorDuringCarrier: 0
  eth-mac-FramesTransmittedOK: 1
  eth-mac-FrameTooLongErrors: 1
  eth-ctrl-MACControlFramesTransmitted: 1
  eth-ctrl-MACControlFramesReceived: 0
  eth-ctrl-UnsupportedOpcodesReceived: 1
  rmon-etherStatsUndersizePkts: 1
  rmon-etherStatsJabbers: 0
  rmon-rx-etherStatsPkts64Octets: 1
  rmon-rx-etherStatsPkts65to127Octets: 0
  rmon-rx-etherStatsPkts128to255Octets: 0
  rmon-tx-etherStatsPkts64Octets: 2
  rmon-tx-etherStatsPkts65to127Octets: 3
  rmon-tx-etherStatsPkts128to255Octets: 0

Driver-defined statistics
-------------------------

+125 −0
Original line number Diff line number Diff line
@@ -3990,6 +3990,127 @@ void bnxt_ethtool_init(struct bnxt *bp)
	mutex_unlock(&bp->hwrm_cmd_lock);
}

static void bnxt_get_eth_phy_stats(struct net_device *dev,
				   struct ethtool_eth_phy_stats *phy_stats)
{
	struct bnxt *bp = netdev_priv(dev);
	u64 *rx;

	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS_EXT))
		return;

	rx = bp->rx_port_stats_ext.sw_stats;
	phy_stats->SymbolErrorDuringCarrier =
		*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_pcs_symbol_err));
}

static void bnxt_get_eth_mac_stats(struct net_device *dev,
				   struct ethtool_eth_mac_stats *mac_stats)
{
	struct bnxt *bp = netdev_priv(dev);
	u64 *rx, *tx;

	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
		return;

	rx = bp->port_stats.sw_stats;
	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;

	mac_stats->FramesReceivedOK =
		BNXT_GET_RX_PORT_STATS64(rx, rx_good_frames);
	mac_stats->FramesTransmittedOK =
		BNXT_GET_TX_PORT_STATS64(tx, tx_good_frames);
}

static void bnxt_get_eth_ctrl_stats(struct net_device *dev,
				    struct ethtool_eth_ctrl_stats *ctrl_stats)
{
	struct bnxt *bp = netdev_priv(dev);
	u64 *rx;

	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
		return;

	rx = bp->port_stats.sw_stats;
	ctrl_stats->MACControlFramesReceived =
		BNXT_GET_RX_PORT_STATS64(rx, rx_ctrl_frames);
}

static const struct ethtool_rmon_hist_range bnxt_rmon_ranges[] = {
	{    0,    64 },
	{   65,   127 },
	{  128,   255 },
	{  256,   511 },
	{  512,  1023 },
	{ 1024,  1518 },
	{ 1519,  2047 },
	{ 2048,  4095 },
	{ 4096,  9216 },
	{ 9217, 16383 },
	{}
};

static void bnxt_get_rmon_stats(struct net_device *dev,
				struct ethtool_rmon_stats *rmon_stats,
				const struct ethtool_rmon_hist_range **ranges)
{
	struct bnxt *bp = netdev_priv(dev);
	u64 *rx, *tx;

	if (BNXT_VF(bp) || !(bp->flags & BNXT_FLAG_PORT_STATS))
		return;

	rx = bp->port_stats.sw_stats;
	tx = bp->port_stats.sw_stats + BNXT_TX_PORT_STATS_BYTE_OFFSET / 8;

	rmon_stats->jabbers =
		BNXT_GET_RX_PORT_STATS64(rx, rx_jbr_frames);
	rmon_stats->oversize_pkts =
		BNXT_GET_RX_PORT_STATS64(rx, rx_ovrsz_frames);
	rmon_stats->undersize_pkts =
		BNXT_GET_RX_PORT_STATS64(rx, rx_undrsz_frames);

	rmon_stats->hist[0] = BNXT_GET_RX_PORT_STATS64(rx, rx_64b_frames);
	rmon_stats->hist[1] = BNXT_GET_RX_PORT_STATS64(rx, rx_65b_127b_frames);
	rmon_stats->hist[2] = BNXT_GET_RX_PORT_STATS64(rx, rx_128b_255b_frames);
	rmon_stats->hist[3] = BNXT_GET_RX_PORT_STATS64(rx, rx_256b_511b_frames);
	rmon_stats->hist[4] =
		BNXT_GET_RX_PORT_STATS64(rx, rx_512b_1023b_frames);
	rmon_stats->hist[5] =
		BNXT_GET_RX_PORT_STATS64(rx, rx_1024b_1518b_frames);
	rmon_stats->hist[6] =
		BNXT_GET_RX_PORT_STATS64(rx, rx_1519b_2047b_frames);
	rmon_stats->hist[7] =
		BNXT_GET_RX_PORT_STATS64(rx, rx_2048b_4095b_frames);
	rmon_stats->hist[8] =
		BNXT_GET_RX_PORT_STATS64(rx, rx_4096b_9216b_frames);
	rmon_stats->hist[9] =
		BNXT_GET_RX_PORT_STATS64(rx, rx_9217b_16383b_frames);

	rmon_stats->hist_tx[0] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_64b_frames);
	rmon_stats->hist_tx[1] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_65b_127b_frames);
	rmon_stats->hist_tx[2] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_128b_255b_frames);
	rmon_stats->hist_tx[3] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_256b_511b_frames);
	rmon_stats->hist_tx[4] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_512b_1023b_frames);
	rmon_stats->hist_tx[5] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_1024b_1518b_frames);
	rmon_stats->hist_tx[6] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_1519b_2047b_frames);
	rmon_stats->hist_tx[7] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_2048b_4095b_frames);
	rmon_stats->hist_tx[8] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_4096b_9216b_frames);
	rmon_stats->hist_tx[9] =
		BNXT_GET_TX_PORT_STATS64(tx, tx_9217b_16383b_frames);

	*ranges = bnxt_rmon_ranges;
}

void bnxt_ethtool_free(struct bnxt *bp)
{
	kfree(bp->test_info);
@@ -4049,4 +4170,8 @@ const struct ethtool_ops bnxt_ethtool_ops = {
	.set_dump		= bnxt_set_dump,
	.get_dump_flag		= bnxt_get_dump_flag,
	.get_dump_data		= bnxt_get_dump_data,
	.get_eth_phy_stats	= bnxt_get_eth_phy_stats,
	.get_eth_mac_stats	= bnxt_get_eth_mac_stats,
	.get_eth_ctrl_stats	= bnxt_get_eth_ctrl_stats,
	.get_rmon_stats		= bnxt_get_rmon_stats,
};
+37 −0
Original line number Diff line number Diff line
@@ -2295,6 +2295,39 @@ mlx5e_get_link_ext_state(struct net_device *dev,
	return -ENODATA;
}

static void mlx5e_get_eth_phy_stats(struct net_device *netdev,
				    struct ethtool_eth_phy_stats *phy_stats)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);

	mlx5e_stats_eth_phy_get(priv, phy_stats);
}

static void mlx5e_get_eth_mac_stats(struct net_device *netdev,
				    struct ethtool_eth_mac_stats *mac_stats)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);

	mlx5e_stats_eth_mac_get(priv, mac_stats);
}

static void mlx5e_get_eth_ctrl_stats(struct net_device *netdev,
				     struct ethtool_eth_ctrl_stats *ctrl_stats)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);

	mlx5e_stats_eth_ctrl_get(priv, ctrl_stats);
}

static void mlx5e_get_rmon_stats(struct net_device *netdev,
				 struct ethtool_rmon_stats *rmon_stats,
				 const struct ethtool_rmon_hist_range **ranges)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);

	mlx5e_stats_rmon_get(priv, rmon_stats, ranges);
}

const struct ethtool_ops mlx5e_ethtool_ops = {
	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
				     ETHTOOL_COALESCE_MAX_FRAMES |
@@ -2340,4 +2373,8 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
	.get_fec_stats     = mlx5e_get_fec_stats,
	.get_fecparam      = mlx5e_get_fecparam,
	.set_fecparam      = mlx5e_set_fecparam,
	.get_eth_phy_stats = mlx5e_get_eth_phy_stats,
	.get_eth_mac_stats = mlx5e_get_eth_mac_stats,
	.get_eth_ctrl_stats = mlx5e_get_eth_ctrl_stats,
	.get_rmon_stats    = mlx5e_get_rmon_stats,
};
+135 −7
Original line number Diff line number Diff line
@@ -775,21 +775,29 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(802_3)
		MLX5_BYTE_OFF(ppcnt_reg,		\
			      counter_set.set.c##_high)))

void mlx5e_stats_pause_get(struct mlx5e_priv *priv,
			   struct ethtool_pause_stats *pause_stats)
static int mlx5e_stats_get_ieee(struct mlx5_core_dev *mdev,
				u32 *ppcnt_ieee_802_3)
{
	u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
	struct mlx5_core_dev *mdev = priv->mdev;
	u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {};
	int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);

	if (!MLX5_BASIC_PPCNT_SUPPORTED(mdev))
		return;
		return -EOPNOTSUPP;

	MLX5_SET(ppcnt_reg, in, local_port, 1);
	MLX5_SET(ppcnt_reg, in, grp, MLX5_IEEE_802_3_COUNTERS_GROUP);
	mlx5_core_access_reg(mdev, in, sz, ppcnt_ieee_802_3,
	return mlx5_core_access_reg(mdev, in, sz, ppcnt_ieee_802_3,
				    sz, MLX5_REG_PPCNT, 0, 0);
}

void mlx5e_stats_pause_get(struct mlx5e_priv *priv,
			   struct ethtool_pause_stats *pause_stats)
{
	u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
	struct mlx5_core_dev *mdev = priv->mdev;

	if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
		return;

	pause_stats->tx_pause_frames =
		MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
@@ -801,6 +809,73 @@ void mlx5e_stats_pause_get(struct mlx5e_priv *priv,
				      a_pause_mac_ctrl_frames_received);
}

void mlx5e_stats_eth_phy_get(struct mlx5e_priv *priv,
			     struct ethtool_eth_phy_stats *phy_stats)
{
	u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
	struct mlx5_core_dev *mdev = priv->mdev;

	if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
		return;

	phy_stats->SymbolErrorDuringCarrier =
		MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
				      eth_802_3_cntrs_grp_data_layout,
				      a_symbol_error_during_carrier);
}

void mlx5e_stats_eth_mac_get(struct mlx5e_priv *priv,
			     struct ethtool_eth_mac_stats *mac_stats)
{
	u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
	struct mlx5_core_dev *mdev = priv->mdev;

	if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
		return;

#define RD(name)							\
	MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,				\
			      eth_802_3_cntrs_grp_data_layout,		\
			      name)

	mac_stats->FramesTransmittedOK	= RD(a_frames_transmitted_ok);
	mac_stats->FramesReceivedOK	= RD(a_frames_received_ok);
	mac_stats->FrameCheckSequenceErrors = RD(a_frame_check_sequence_errors);
	mac_stats->OctetsTransmittedOK	= RD(a_octets_transmitted_ok);
	mac_stats->OctetsReceivedOK	= RD(a_octets_received_ok);
	mac_stats->MulticastFramesXmittedOK = RD(a_multicast_frames_xmitted_ok);
	mac_stats->BroadcastFramesXmittedOK = RD(a_broadcast_frames_xmitted_ok);
	mac_stats->MulticastFramesReceivedOK = RD(a_multicast_frames_received_ok);
	mac_stats->BroadcastFramesReceivedOK = RD(a_broadcast_frames_received_ok);
	mac_stats->InRangeLengthErrors	= RD(a_in_range_length_errors);
	mac_stats->OutOfRangeLengthField = RD(a_out_of_range_length_field);
	mac_stats->FrameTooLongErrors	= RD(a_frame_too_long_errors);
#undef RD
}

void mlx5e_stats_eth_ctrl_get(struct mlx5e_priv *priv,
			      struct ethtool_eth_ctrl_stats *ctrl_stats)
{
	u32 ppcnt_ieee_802_3[MLX5_ST_SZ_DW(ppcnt_reg)];
	struct mlx5_core_dev *mdev = priv->mdev;

	if (mlx5e_stats_get_ieee(mdev, ppcnt_ieee_802_3))
		return;

	ctrl_stats->MACControlFramesTransmitted =
		MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
				      eth_802_3_cntrs_grp_data_layout,
				      a_mac_control_frames_transmitted);
	ctrl_stats->MACControlFramesReceived =
		MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
				      eth_802_3_cntrs_grp_data_layout,
				      a_mac_control_frames_received);
	ctrl_stats->UnsupportedOpcodesReceived =
		MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
				      eth_802_3_cntrs_grp_data_layout,
				      a_unsupported_opcodes_received);
}

#define PPORT_2863_OFF(c) \
	MLX5_BYTE_OFF(ppcnt_reg, \
		      counter_set.eth_2863_cntrs_grp_data_layout.c##_high)
@@ -912,6 +987,59 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(2819)
	mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
}

static const struct ethtool_rmon_hist_range mlx5e_rmon_ranges[] = {
	{    0,    64 },
	{   65,   127 },
	{  128,   255 },
	{  256,   511 },
	{  512,  1023 },
	{ 1024,  1518 },
	{ 1519,  2047 },
	{ 2048,  4095 },
	{ 4096,  8191 },
	{ 8192, 10239 },
	{}
};

void mlx5e_stats_rmon_get(struct mlx5e_priv *priv,
			  struct ethtool_rmon_stats *rmon,
			  const struct ethtool_rmon_hist_range **ranges)
{
	u32 ppcnt_RFC_2819_counters[MLX5_ST_SZ_DW(ppcnt_reg)];
	struct mlx5_core_dev *mdev = priv->mdev;
	u32 in[MLX5_ST_SZ_DW(ppcnt_reg)] = {0};
	int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);

	MLX5_SET(ppcnt_reg, in, local_port, 1);
	MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2819_COUNTERS_GROUP);
	if (mlx5_core_access_reg(mdev, in, sz, ppcnt_RFC_2819_counters,
				 sz, MLX5_REG_PPCNT, 0, 0))
		return;

#define RD(name)						\
	MLX5E_READ_CTR64_BE_F(ppcnt_RFC_2819_counters,		\
			      eth_2819_cntrs_grp_data_layout,	\
			      name)

	rmon->undersize_pkts	= RD(ether_stats_undersize_pkts);
	rmon->fragments		= RD(ether_stats_fragments);
	rmon->jabbers		= RD(ether_stats_jabbers);

	rmon->hist[0]		= RD(ether_stats_pkts64octets);
	rmon->hist[1]		= RD(ether_stats_pkts65to127octets);
	rmon->hist[2]		= RD(ether_stats_pkts128to255octets);
	rmon->hist[3]		= RD(ether_stats_pkts256to511octets);
	rmon->hist[4]		= RD(ether_stats_pkts512to1023octets);
	rmon->hist[5]		= RD(ether_stats_pkts1024to1518octets);
	rmon->hist[6]		= RD(ether_stats_pkts1519to2047octets);
	rmon->hist[7]		= RD(ether_stats_pkts2048to4095octets);
	rmon->hist[8]		= RD(ether_stats_pkts4096to8191octets);
	rmon->hist[9]		= RD(ether_stats_pkts8192to10239octets);
#undef RD

	*ranges = mlx5e_rmon_ranges;
}

#define PPORT_PHY_STATISTICAL_OFF(c) \
	MLX5_BYTE_OFF(ppcnt_reg, \
		      counter_set.phys_layer_statistical_cntrs.c##_high)
Loading