[PATCH 3/3] can: xilinx_can: Add debugfs support for ECC

From: Srinivas Goud
Date: Mon Jun 12 2023 - 07:49:31 EST


Create debugfs entry for reading all the FIFO ECC errors.

Signed-off-by: Srinivas Goud <srinivas.goud@xxxxxxx>
---
drivers/net/can/xilinx_can.c | 62 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
index 311e435..f7bf31a 100644
--- a/drivers/net/can/xilinx_can.c
+++ b/drivers/net/can/xilinx_can.c
@@ -29,6 +29,7 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/pm_runtime.h>
+#include <linux/debugfs.h>

#define DRIVER_NAME "xilinx_can"

@@ -183,6 +184,9 @@ enum xcan_reg {
#define XCAN_FLAG_RX_FIFO_MULTI 0x0010
#define XCAN_FLAG_CANFD_2 0x0020

+/* ECC counters buffer length */
+#define XCAN_ECC_CNT_BUF_LEN 100
+
enum xcan_ip_type {
XAXI_CAN = 0,
XZYNQ_CANPS,
@@ -222,6 +226,7 @@ struct xcan_devtype_data {
* @ecc_1bit_txolfifo_cnt: TXOLFIFO 1bit ECC count
* @ecc_2bit_txtlfifo_cnt: TXTLFIFO 2bit ECC count
* @ecc_1bit_txtlfifo_cnt: TXTLFIFO 1bit ECC count
+ * @debugfs: Directory entry for debugfs
*/
struct xcan_priv {
struct can_priv can;
@@ -246,6 +251,7 @@ struct xcan_priv {
u32 ecc_1bit_txolfifo_cnt;
u32 ecc_2bit_txtlfifo_cnt;
u32 ecc_1bit_txtlfifo_cnt;
+ struct dentry *debugfs;
};

/* CAN Bittiming constants as per Xilinx CAN specs */
@@ -1736,6 +1742,56 @@ static int __maybe_unused xcan_runtime_resume(struct device *dev)
return 0;
}

+static ssize_t read_ecc_cnt_status(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned int len = 0, buf_len = XCAN_ECC_CNT_BUF_LEN;
+ struct net_device *ndev = file->private_data;
+ struct xcan_priv *priv = netdev_priv(ndev);
+ ssize_t ret_cnt;
+ char *buf;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len = scnprintf(buf + len, buf_len - len,
+ "%d\n", priv->ecc_2bit_rxfifo_cnt);
+ len += scnprintf(buf + len, buf_len - len,
+ "%d\n", priv->ecc_1bit_rxfifo_cnt);
+ len += scnprintf(buf + len, buf_len - len,
+ "%d\n", priv->ecc_2bit_txolfifo_cnt);
+ len += scnprintf(buf + len, buf_len - len,
+ "%d\n", priv->ecc_1bit_txolfifo_cnt);
+ len += scnprintf(buf + len, buf_len - len,
+ "%d\n", priv->ecc_2bit_txtlfifo_cnt);
+ len += scnprintf(buf + len, buf_len - len,
+ "%d\n", priv->ecc_1bit_txtlfifo_cnt);
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+
+ return ret_cnt;
+}
+
+static const struct file_operations read_ecc_fops = {
+ .open = simple_open,
+ .read = read_ecc_cnt_status,
+ .llseek = generic_file_llseek,
+};
+
+static void setup_debugfs(struct net_device *ndev)
+{
+ struct xcan_priv *priv = netdev_priv(ndev);
+
+ priv->debugfs = debugfs_create_dir(dev_name(priv->dev), NULL);
+ if (!priv->debugfs)
+ return;
+
+ debugfs_create_file("read_ecc_cnt", 0644, priv->debugfs,
+ ndev, &read_ecc_fops);
+}
+
static const struct dev_pm_ops xcan_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(xcan_suspend, xcan_resume)
SET_RUNTIME_PM_OPS(xcan_runtime_suspend, xcan_runtime_resume, NULL)
@@ -1974,10 +2030,12 @@ static int xcan_probe(struct platform_device *pdev)
priv->reg_base, ndev->irq, priv->can.clock.freq,
hw_tx_max, priv->tx_max);

- if (priv->ecc_enable)
+ if (priv->ecc_enable) {
+ setup_debugfs(ndev);
/* Reset FIFO ECC counters */
priv->write_reg(priv, XCAN_ECC_CFG_OFFSET, XCAN_ECC_CFG_REECRX_MASK |
XCAN_ECC_CFG_REECTXOL_MASK | XCAN_ECC_CFG_REECTXTL_MASK);
+ }

return 0;

@@ -2000,7 +2058,9 @@ static int xcan_probe(struct platform_device *pdev)
static int xcan_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct xcan_priv *priv = netdev_priv(ndev);

+ debugfs_remove_recursive(priv->debugfs);
unregister_candev(ndev);
pm_runtime_disable(&pdev->dev);
free_candev(ndev);
--
2.1.1