can: xilinx_can: Add ethtool stats interface for ECC errors

Add ethtool stats interface for reading FIFO 1bit/2bit ECC errors
information.

Signed-off-by: Srinivas Goud <srinivas.goud@amd.com>
Link: https://lore.kernel.org/all/20240213-xilinx_ecc-v8-3-8d75f8b80771@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Srinivas Goud 2024-02-13 11:36:45 +01:00 committed by Marc Kleine-Budde
parent 8e6fbf7f66
commit e1d1698eb3
1 changed files with 64 additions and 0 deletions

View File

@ -228,6 +228,7 @@ struct xcan_devtype_data {
* @transceiver: Optional pointer to associated CAN transceiver
* @rstc: Pointer to reset control
* @ecc_enable: ECC enable flag
* @syncp: synchronization for ECC error stats
* @ecc_rx_2_bit_errors: RXFIFO 2bit ECC count
* @ecc_rx_1_bit_errors: RXFIFO 1bit ECC count
* @ecc_txol_2_bit_errors: TXOLFIFO 2bit ECC count
@ -254,6 +255,7 @@ struct xcan_priv {
struct phy *transceiver;
struct reset_control *rstc;
bool ecc_enable;
struct u64_stats_sync syncp;
u64_stats_t ecc_rx_2_bit_errors;
u64_stats_t ecc_rx_1_bit_errors;
u64_stats_t ecc_txol_2_bit_errors;
@ -347,6 +349,24 @@ static const struct can_tdc_const xcan_tdc_const_canfd2 = {
.tdcf_max = 0,
};
enum xcan_stats_type {
XCAN_ECC_RX_2_BIT_ERRORS,
XCAN_ECC_RX_1_BIT_ERRORS,
XCAN_ECC_TXOL_2_BIT_ERRORS,
XCAN_ECC_TXOL_1_BIT_ERRORS,
XCAN_ECC_TXTL_2_BIT_ERRORS,
XCAN_ECC_TXTL_1_BIT_ERRORS,
};
static const char xcan_priv_flags_strings[][ETH_GSTRING_LEN] = {
[XCAN_ECC_RX_2_BIT_ERRORS] = "ecc_rx_2_bit_errors",
[XCAN_ECC_RX_1_BIT_ERRORS] = "ecc_rx_1_bit_errors",
[XCAN_ECC_TXOL_2_BIT_ERRORS] = "ecc_txol_2_bit_errors",
[XCAN_ECC_TXOL_1_BIT_ERRORS] = "ecc_txol_1_bit_errors",
[XCAN_ECC_TXTL_2_BIT_ERRORS] = "ecc_txtl_2_bit_errors",
[XCAN_ECC_TXTL_1_BIT_ERRORS] = "ecc_txtl_1_bit_errors",
};
/**
* xcan_write_reg_le - Write a value to the device register little endian
* @priv: Driver private data structure
@ -1182,6 +1202,8 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
priv->write_reg(priv, XCAN_ECC_CFG_OFFSET, XCAN_ECC_CFG_REECRX_MASK |
XCAN_ECC_CFG_REECTXOL_MASK | XCAN_ECC_CFG_REECTXTL_MASK);
u64_stats_update_begin(&priv->syncp);
if (isr & XCAN_IXR_E2BERX_MASK) {
u64_stats_add(&priv->ecc_rx_2_bit_errors,
FIELD_GET(XCAN_ECC_2BIT_CNT_MASK, reg_rx_ecc));
@ -1211,6 +1233,8 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
u64_stats_add(&priv->ecc_txtl_1_bit_errors,
FIELD_GET(XCAN_ECC_1BIT_CNT_MASK, reg_txtl_ecc));
}
u64_stats_update_end(&priv->syncp);
}
if (cf.can_id) {
@ -1637,6 +1661,43 @@ static int xcan_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv)
return 0;
}
static void xcan_get_strings(struct net_device *ndev, u32 stringset, u8 *buf)
{
switch (stringset) {
case ETH_SS_STATS:
memcpy(buf, &xcan_priv_flags_strings,
sizeof(xcan_priv_flags_strings));
}
}
static int xcan_get_sset_count(struct net_device *netdev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
return ARRAY_SIZE(xcan_priv_flags_strings);
default:
return -EOPNOTSUPP;
}
}
static void xcan_get_ethtool_stats(struct net_device *ndev,
struct ethtool_stats *stats, u64 *data)
{
struct xcan_priv *priv = netdev_priv(ndev);
unsigned int start;
do {
start = u64_stats_fetch_begin(&priv->syncp);
data[XCAN_ECC_RX_2_BIT_ERRORS] = u64_stats_read(&priv->ecc_rx_2_bit_errors);
data[XCAN_ECC_RX_1_BIT_ERRORS] = u64_stats_read(&priv->ecc_rx_1_bit_errors);
data[XCAN_ECC_TXOL_2_BIT_ERRORS] = u64_stats_read(&priv->ecc_txol_2_bit_errors);
data[XCAN_ECC_TXOL_1_BIT_ERRORS] = u64_stats_read(&priv->ecc_txol_1_bit_errors);
data[XCAN_ECC_TXTL_2_BIT_ERRORS] = u64_stats_read(&priv->ecc_txtl_2_bit_errors);
data[XCAN_ECC_TXTL_1_BIT_ERRORS] = u64_stats_read(&priv->ecc_txtl_1_bit_errors);
} while (u64_stats_fetch_retry(&priv->syncp, start));
}
static const struct net_device_ops xcan_netdev_ops = {
.ndo_open = xcan_open,
.ndo_stop = xcan_close,
@ -1646,6 +1707,9 @@ static const struct net_device_ops xcan_netdev_ops = {
static const struct ethtool_ops xcan_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
.get_strings = xcan_get_strings,
.get_sset_count = xcan_get_sset_count,
.get_ethtool_stats = xcan_get_ethtool_stats,
};
/**