From: Srinivas Goud <srinivas.goud@xxxxxxx> Add ethtool stats interface for reading FIFO 1bit/2bit ECC errors information. Signed-off-by: Srinivas Goud <srinivas.goud@xxxxxxx> Signed-off-by: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx> --- drivers/net/can/xilinx_can.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index af2af4eade3c..fae0120473f8 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -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, }; /** -- 2.43.0