Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: rockchip_canfd: add stats support for errata workarounds

The driver contains workarounds for some of the rk3568v2 errata. Add
ethtool-based statistics ("ethtool -S") to track how often an erratum
workaround was needed.

Tested-by: Alibek Omarov <a1ba.omarov@gmail.com>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patch.msgid.link/20240904-rockchip-canfd-v5-15-8ae22bcb27cc@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

+102 -1
+1
drivers/net/can/rockchip/Makefile
··· 4 4 5 5 rockchip_canfd-objs := 6 6 rockchip_canfd-objs += rockchip_canfd-core.o 7 + rockchip_canfd-objs += rockchip_canfd-ethtool.o 7 8 rockchip_canfd-objs += rockchip_canfd-rx.o 8 9 rockchip_canfd-objs += rockchip_canfd-timestamp.o 9 10 rockchip_canfd-objs += rockchip_canfd-tx.o
+2
drivers/net/can/rockchip/rockchip_canfd-core.c
··· 800 800 if (err) 801 801 goto out_pm_runtime_disable; 802 802 803 + rkcanfd_ethtool_init(priv); 804 + 803 805 err = register_candev(ndev); 804 806 if (err) 805 807 goto out_pm_runtime_put_sync;
+73
drivers/net/can/rockchip/rockchip_canfd-ethtool.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // Copyright (c) 2023, 2024 Pengutronix, 4 + // Marc Kleine-Budde <kernel@pengutronix.de> 5 + // 6 + 7 + #include <linux/ethtool.h> 8 + 9 + #include "rockchip_canfd.h" 10 + 11 + enum rkcanfd_stats_type { 12 + RKCANFD_STATS_TYPE_RX_FIFO_EMPTY_ERRORS, 13 + RKCANFD_STATS_TYPE_TX_EXTENDED_AS_STANDARD_ERRORS, 14 + }; 15 + 16 + static const char rkcanfd_stats_strings[][ETH_GSTRING_LEN] = { 17 + [RKCANFD_STATS_TYPE_RX_FIFO_EMPTY_ERRORS] = "rx_fifo_empty_errors", 18 + [RKCANFD_STATS_TYPE_TX_EXTENDED_AS_STANDARD_ERRORS] = "tx_extended_as_standard_errors", 19 + }; 20 + 21 + static void 22 + rkcanfd_ethtool_get_strings(struct net_device *ndev, u32 stringset, u8 *buf) 23 + { 24 + switch (stringset) { 25 + case ETH_SS_STATS: 26 + memcpy(buf, rkcanfd_stats_strings, 27 + sizeof(rkcanfd_stats_strings)); 28 + } 29 + } 30 + 31 + static int rkcanfd_ethtool_get_sset_count(struct net_device *netdev, int sset) 32 + { 33 + switch (sset) { 34 + case ETH_SS_STATS: 35 + return ARRAY_SIZE(rkcanfd_stats_strings); 36 + default: 37 + return -EOPNOTSUPP; 38 + } 39 + } 40 + 41 + static void 42 + rkcanfd_ethtool_get_ethtool_stats(struct net_device *ndev, 43 + struct ethtool_stats *stats, u64 *data) 44 + { 45 + struct rkcanfd_priv *priv = netdev_priv(ndev); 46 + struct rkcanfd_stats *rkcanfd_stats; 47 + unsigned int start; 48 + 49 + rkcanfd_stats = &priv->stats; 50 + 51 + do { 52 + start = u64_stats_fetch_begin(&rkcanfd_stats->syncp); 53 + 54 + data[RKCANFD_STATS_TYPE_RX_FIFO_EMPTY_ERRORS] = 55 + u64_stats_read(&rkcanfd_stats->rx_fifo_empty_errors); 56 + data[RKCANFD_STATS_TYPE_TX_EXTENDED_AS_STANDARD_ERRORS] = 57 + u64_stats_read(&rkcanfd_stats->tx_extended_as_standard_errors); 58 + } while (u64_stats_fetch_retry(&rkcanfd_stats->syncp, start)); 59 + } 60 + 61 + static const struct ethtool_ops rkcanfd_ethtool_ops = { 62 + .get_ts_info = ethtool_op_get_ts_info, 63 + .get_strings = rkcanfd_ethtool_get_strings, 64 + .get_sset_count = rkcanfd_ethtool_get_sset_count, 65 + .get_ethtool_stats = rkcanfd_ethtool_get_ethtool_stats, 66 + }; 67 + 68 + void rkcanfd_ethtool_init(struct rkcanfd_priv *priv) 69 + { 70 + priv->ndev->ethtool_ops = &rkcanfd_ethtool_ops; 71 + 72 + u64_stats_init(&priv->stats.syncp); 73 + }
+12 -1
drivers/net/can/rockchip/rockchip_canfd-rx.c
··· 96 96 bool *tx_done) 97 97 { 98 98 struct net_device_stats *stats = &priv->ndev->stats; 99 + struct rkcanfd_stats *rkcanfd_stats = &priv->stats; 99 100 const struct canfd_frame *cfd_nominal; 100 101 const struct sk_buff *skb; 101 102 unsigned int tx_tail; ··· 167 166 return 0; 168 167 169 168 /* Affected by Erratum 6 */ 169 + u64_stats_update_begin(&rkcanfd_stats->syncp); 170 + u64_stats_inc(&rkcanfd_stats->tx_extended_as_standard_errors); 171 + u64_stats_update_end(&rkcanfd_stats->syncp); 170 172 171 173 /* Manual handling of CAN Bus Error counters. See 172 174 * rkcanfd_get_corrected_berr_counter() for detailed ··· 215 211 cfd->data, sizeof(cfd->data)); 216 212 217 213 /* Erratum 5: Counters for TXEFIFO and RXFIFO may be wrong */ 218 - if (rkcanfd_fifo_header_empty(header)) 214 + if (rkcanfd_fifo_header_empty(header)) { 215 + struct rkcanfd_stats *rkcanfd_stats = &priv->stats; 216 + 217 + u64_stats_update_begin(&rkcanfd_stats->syncp); 218 + u64_stats_inc(&rkcanfd_stats->rx_fifo_empty_errors); 219 + u64_stats_update_end(&rkcanfd_stats->syncp); 220 + 219 221 return 0; 222 + } 220 223 221 224 len = rkcanfd_fifo_header_to_cfd_header(priv, header, cfd); 222 225
+14
drivers/net/can/rockchip/rockchip_canfd.h
··· 446 446 u32 ts; 447 447 }; 448 448 449 + struct rkcanfd_stats { 450 + struct u64_stats_sync syncp; 451 + 452 + /* Erratum 5 */ 453 + u64_stats_t rx_fifo_empty_errors; 454 + 455 + /* Erratum 6 */ 456 + u64_stats_t tx_extended_as_standard_errors; 457 + }; 458 + 449 459 struct rkcanfd_priv { 450 460 struct can_priv can; 451 461 struct can_rx_offload offload; ··· 470 460 struct rkcanfd_devtype_data devtype_data; 471 461 472 462 struct can_berr_counter bec; 463 + 464 + struct rkcanfd_stats stats; 473 465 474 466 struct reset_control *reset; 475 467 struct clk_bulk_data *clks; ··· 526 514 { 527 515 return RKCANFD_TXFIFO_DEPTH - rkcanfd_get_tx_pending(priv); 528 516 } 517 + 518 + void rkcanfd_ethtool_init(struct rkcanfd_priv *priv); 529 519 530 520 int rkcanfd_handle_rx_int(struct rkcanfd_priv *priv); 531 521