Skip to content

Commit

Permalink
Merge branch 'ehtool-fec-stats'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
ethtool: add standard FEC statistics

This set adds uAPI for reporting standard FEC statistics, and
implements it in a handful of drivers.

The statistics are taken from the IEEE standard, with one
extra seemingly popular but not standard statistics added.

The implementation is similar to that of the pause frame
statistics, user requests the stats by setting a bit
(ETHTOOL_FLAG_STATS) in the common ethtool header of
ETHTOOL_MSG_FEC_GET.

Since standard defines the statistics per lane what's
reported is both total and per-lane counters:

 # ethtool -I --show-fec eth0
 FEC parameters for eth0:
 Configured FEC encodings: None
 Active FEC encoding: None
 Statistics:
  corrected_blocks: 256
    Lane 0: 255
    Lane 1: 1
  uncorrectable_blocks: 145
    Lane 0: 128
    Lane 1: 17

v2: check for errors in mlx5 register access
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 16, 2021
2 parents 38ebcf5 + 1703bb5 commit 392c36e
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 12 deletions.
21 changes: 21 additions & 0 deletions Documentation/networking/ethtool-netlink.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,7 @@ Kernel response contents:
``ETHTOOL_A_FEC_MODES`` bitset configured modes
``ETHTOOL_A_FEC_AUTO`` bool FEC mode auto selection
``ETHTOOL_A_FEC_ACTIVE`` u32 index of active FEC mode
``ETHTOOL_A_FEC_STATS`` nested FEC statistics
===================================== ====== ==========================

``ETHTOOL_A_FEC_ACTIVE`` is the bit index of the FEC link mode currently
Expand All @@ -1315,6 +1316,26 @@ This is equivalent to the ``ETHTOOL_FEC_AUTO`` bit of the ioctl interface.
``ETHTOOL_A_FEC_MODES`` carry the current FEC configuration using link mode
bits (rather than old ``ETHTOOL_FEC_*`` bits).

``ETHTOOL_A_FEC_STATS`` are reported if ``ETHTOOL_FLAG_STATS`` was set in
``ETHTOOL_A_HEADER_FLAGS``.
Each attribute carries an array of 64bit statistics. First entry in the array
contains the total number of events on the port, while the following entries
are counters corresponding to lanes/PCS instances. The number of entries in
the array will be:

+--------------+---------------------------------------------+
| `0` | device does not support FEC statistics |
+--------------+---------------------------------------------+
| `1` | device does not support per-lane break down |
+--------------+---------------------------------------------+
| `1 + #lanes` | device has full support for FEC stats |
+--------------+---------------------------------------------+

Drivers fill in the statistics in the following structure:

.. kernel-doc:: include/linux/ethtool.h
:identifiers: ethtool_fec_stats

FEC_SET
=======

Expand Down
2 changes: 2 additions & 0 deletions Documentation/networking/statistics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ the `ETHTOOL_FLAG_STATS` flag in `ETHTOOL_A_HEADER_FLAGS`. Currently
statistics are supported in the following commands:

- `ETHTOOL_MSG_PAUSE_GET`
- `ETHTOOL_MSG_FEC_GET`

debugfs
-------
Expand Down Expand Up @@ -176,3 +177,4 @@ translated to netlink attributes when dumped. Drivers must not overwrite
the statistics they don't report with 0.

- ethtool_pause_stats()
- ethtool_fec_stats()
15 changes: 15 additions & 0 deletions drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,20 @@ static int bnxt_get_fecparam(struct net_device *dev,
return 0;
}

static void bnxt_get_fec_stats(struct net_device *dev,
struct ethtool_fec_stats *fec_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;
fec_stats->corrected_bits.total =
*(rx + BNXT_RX_STATS_EXT_OFFSET(rx_corrected_bits));
}

static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info,
u32 fec)
{
Expand Down Expand Up @@ -3991,6 +4005,7 @@ const struct ethtool_ops bnxt_ethtool_ops = {
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
.get_link_ksettings = bnxt_get_link_ksettings,
.set_link_ksettings = bnxt_set_link_ksettings,
.get_fec_stats = bnxt_get_fec_stats,
.get_fecparam = bnxt_get_fecparam,
.set_fecparam = bnxt_set_fecparam,
.get_pause_stats = bnxt_get_pause_stats,
Expand Down
9 changes: 9 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,14 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
return mlx5_set_port_wol(mdev, mlx5_wol_mode);
}

static void mlx5e_get_fec_stats(struct net_device *netdev,
struct ethtool_fec_stats *fec_stats)
{
struct mlx5e_priv *priv = netdev_priv(netdev);

mlx5e_stats_fec_get(priv, fec_stats);
}

static int mlx5e_get_fecparam(struct net_device *netdev,
struct ethtool_fecparam *fecparam)
{
Expand Down Expand Up @@ -2209,6 +2217,7 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
.self_test = mlx5e_self_test,
.get_msglevel = mlx5e_get_msglevel,
.set_msglevel = mlx5e_set_msglevel,
.get_fec_stats = mlx5e_get_fec_stats,
.get_fecparam = mlx5e_get_fecparam,
.set_fecparam = mlx5e_set_fecparam,
};
29 changes: 27 additions & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -768,10 +768,10 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(802_3)
mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
}

#define MLX5E_READ_CTR64_BE_F(ptr, c) \
#define MLX5E_READ_CTR64_BE_F(ptr, set, c) \
be64_to_cpu(*(__be64 *)((char *)ptr + \
MLX5_BYTE_OFF(ppcnt_reg, \
counter_set.eth_802_3_cntrs_grp_data_layout.c##_high)))
counter_set.set.c##_high)))

void mlx5e_stats_pause_get(struct mlx5e_priv *priv,
struct ethtool_pause_stats *pause_stats)
Expand All @@ -791,9 +791,11 @@ void mlx5e_stats_pause_get(struct mlx5e_priv *priv,

pause_stats->tx_pause_frames =
MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
eth_802_3_cntrs_grp_data_layout,
a_pause_mac_ctrl_frames_transmitted);
pause_stats->rx_pause_frames =
MLX5E_READ_CTR64_BE_F(ppcnt_ieee_802_3,
eth_802_3_cntrs_grp_data_layout,
a_pause_mac_ctrl_frames_received);
}

Expand Down Expand Up @@ -1015,6 +1017,29 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(phy)
mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPCNT, 0, 0);
}

void mlx5e_stats_fec_get(struct mlx5e_priv *priv,
struct ethtool_fec_stats *fec_stats)
{
u32 ppcnt_phy_statistical[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);

if (!MLX5_CAP_PCAM_FEATURE(mdev, ppcnt_statistical_group))
return;

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

fec_stats->corrected_bits.total =
MLX5E_READ_CTR64_BE_F(ppcnt_phy_statistical,
phys_layer_statistical_cntrs,
phy_corrected_bits);
}

#define PPORT_ETH_EXT_OFF(c) \
MLX5_BYTE_OFF(ppcnt_reg, \
counter_set.eth_extended_cntrs_grp_data_layout.c##_high)
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ void mlx5e_stats_update_ndo_stats(struct mlx5e_priv *priv);

void mlx5e_stats_pause_get(struct mlx5e_priv *priv,
struct ethtool_pause_stats *pause_stats);
void mlx5e_stats_fec_get(struct mlx5e_priv *priv,
struct ethtool_fec_stats *fec_stats);

/* Concrete NIC Stats */

Expand Down
17 changes: 17 additions & 0 deletions drivers/net/ethernet/sfc/ef10.c
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,22 @@ static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 *names)
mask, names);
}

static void efx_ef10_get_fec_stats(struct efx_nic *efx,
struct ethtool_fec_stats *fec_stats)
{
DECLARE_BITMAP(mask, EF10_STAT_COUNT);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
u64 *stats = nic_data->stats;

efx_ef10_get_stat_mask(efx, mask);
if (test_bit(EF10_STAT_fec_corrected_errors, mask))
fec_stats->corrected_blocks.total =
stats[EF10_STAT_fec_corrected_errors];
if (test_bit(EF10_STAT_fec_uncorrected_errors, mask))
fec_stats->uncorrectable_blocks.total =
stats[EF10_STAT_fec_uncorrected_errors];
}

static size_t efx_ef10_update_stats_common(struct efx_nic *efx, u64 *full_stats,
struct rtnl_link_stats64 *core_stats)
{
Expand Down Expand Up @@ -4122,6 +4138,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.get_wol = efx_ef10_get_wol,
.set_wol = efx_ef10_set_wol,
.resume_wol = efx_port_dummy_op_void,
.get_fec_stats = efx_ef10_get_fec_stats,
.test_chip = efx_ef10_test_chip,
.test_nvram = efx_mcdi_nvram_test_all,
.mcdi_request = efx_ef10_mcdi_request,
Expand Down
10 changes: 10 additions & 0 deletions drivers/net/ethernet/sfc/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ static int efx_ethtool_set_wol(struct net_device *net_dev,
return efx->type->set_wol(efx, wol->wolopts);
}

static void efx_ethtool_get_fec_stats(struct net_device *net_dev,
struct ethtool_fec_stats *fec_stats)
{
struct efx_nic *efx = netdev_priv(net_dev);

if (efx->type->get_fec_stats)
efx->type->get_fec_stats(efx, fec_stats);
}

static int efx_ethtool_get_ts_info(struct net_device *net_dev,
struct ethtool_ts_info *ts_info)
{
Expand Down Expand Up @@ -257,6 +266,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_module_eeprom = efx_ethtool_get_module_eeprom,
.get_link_ksettings = efx_ethtool_get_link_ksettings,
.set_link_ksettings = efx_ethtool_set_link_ksettings,
.get_fec_stats = efx_ethtool_get_fec_stats,
.get_fecparam = efx_ethtool_get_fecparam,
.set_fecparam = efx_ethtool_set_fecparam,
};
3 changes: 3 additions & 0 deletions drivers/net/ethernet/sfc/net_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,7 @@ struct efx_udp_tunnel {
* @get_wol: Get WoL configuration from driver state
* @set_wol: Push WoL configuration to the NIC
* @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume)
* @get_fec_stats: Get standard FEC statistics.
* @test_chip: Test registers. May use efx_farch_test_registers(), and is
* expected to reset the NIC.
* @test_nvram: Test validity of NVRAM contents
Expand Down Expand Up @@ -1332,6 +1333,8 @@ struct efx_nic_type {
void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol);
int (*set_wol)(struct efx_nic *efx, u32 type);
void (*resume_wol)(struct efx_nic *efx);
void (*get_fec_stats)(struct efx_nic *efx,
struct ethtool_fec_stats *fec_stats);
unsigned int (*check_caps)(const struct efx_nic *efx,
u8 flag,
u32 offset);
Expand Down
46 changes: 46 additions & 0 deletions include/linux/ethtool.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,

#define ETHTOOL_STAT_NOT_SET (~0ULL)

static inline void ethtool_stats_init(u64 *stats, unsigned int n)
{
while (n--)
stats[n] = ETHTOOL_STAT_NOT_SET;
}

/**
* struct ethtool_pause_stats - statistics for IEEE 802.3x pause frames
* @tx_pause_frames: transmitted pause frame count. Reported to user space
Expand All @@ -263,6 +269,39 @@ struct ethtool_pause_stats {
u64 rx_pause_frames;
};

#define ETHTOOL_MAX_LANES 8

/**
* struct ethtool_fec_stats - statistics for IEEE 802.3 FEC
* @corrected_blocks: number of received blocks corrected by FEC
* Reported to user space as %ETHTOOL_A_FEC_STAT_CORRECTED.
*
* Equivalent to `30.5.1.1.17 aFECCorrectedBlocks` from the standard.
*
* @uncorrectable_blocks: number of received blocks FEC was not able to correct
* Reported to user space as %ETHTOOL_A_FEC_STAT_UNCORR.
*
* Equivalent to `30.5.1.1.18 aFECUncorrectableBlocks` from the standard.
*
* @corrected_bits: number of bits corrected by FEC
* Similar to @corrected_blocks but counts individual bit changes,
* not entire FEC data blocks. This is a non-standard statistic.
* Reported to user space as %ETHTOOL_A_FEC_STAT_CORR_BITS.
*
* @lane: per-lane/PCS-instance counts as defined by the standard
* @total: error counts for the entire port, for drivers incapable of reporting
* per-lane stats
*
* Drivers should fill in either only total or per-lane statistics, core
* will take care of adding lane values up to produce the total.
*/
struct ethtool_fec_stats {
struct ethtool_fec_stat {
u64 total;
u64 lanes[ETHTOOL_MAX_LANES];
} corrected_blocks, uncorrectable_blocks, corrected_bits;
};

#define ETH_MODULE_EEPROM_PAGE_LEN 128
#define ETH_MODULE_MAX_I2C_ADDRESS 0x7f

Expand Down Expand Up @@ -433,6 +472,11 @@ struct ethtool_module_eeprom {
* ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter),
* any change to them will be overwritten by kernel. Returns a negative
* error code or zero.
* @get_fec_stats: Report FEC statistics.
* Core will sum up per-lane stats to get the total.
* 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_fecparam: Get the network device Forward Error Correction parameters.
* @set_fecparam: Set the network device Forward Error Correction parameters.
* @get_ethtool_phy_stats: Return extended statistics about the PHY device.
Expand Down Expand Up @@ -538,6 +582,8 @@ struct ethtool_ops {
struct ethtool_link_ksettings *);
int (*set_link_ksettings)(struct net_device *,
const struct ethtool_link_ksettings *);
void (*get_fec_stats)(struct net_device *dev,
struct ethtool_fec_stats *fec_stats);
int (*get_fecparam)(struct net_device *,
struct ethtool_fecparam *);
int (*set_fecparam)(struct net_device *,
Expand Down
14 changes: 14 additions & 0 deletions include/uapi/linux/ethtool_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -643,11 +643,25 @@ enum {
ETHTOOL_A_FEC_MODES, /* bitset */
ETHTOOL_A_FEC_AUTO, /* u8 */
ETHTOOL_A_FEC_ACTIVE, /* u32 */
ETHTOOL_A_FEC_STATS, /* nest - _A_FEC_STAT */

__ETHTOOL_A_FEC_CNT,
ETHTOOL_A_FEC_MAX = (__ETHTOOL_A_FEC_CNT - 1)
};

enum {
ETHTOOL_A_FEC_STAT_UNSPEC,
ETHTOOL_A_FEC_STAT_PAD,

ETHTOOL_A_FEC_STAT_CORRECTED, /* array, u64 */
ETHTOOL_A_FEC_STAT_UNCORR, /* array, u64 */
ETHTOOL_A_FEC_STAT_CORR_BITS, /* array, u64 */

/* add new constants above here */
__ETHTOOL_A_FEC_STAT_CNT,
ETHTOOL_A_FEC_STAT_MAX = (__ETHTOOL_A_FEC_STAT_CNT - 1)
};

/* MODULE EEPROM */

enum {
Expand Down
Loading

0 comments on commit 392c36e

Please sign in to comment.