From ef3a98b15702643df6ce1e7f65253486d361b0cd Mon Sep 17 00:00:00 2001 From: Suraj Jaiswal Date: Tue, 15 Dec 2020 18:09:00 +0530 Subject: [PATCH] net: stmmac: Add debugfs entries Add RGMII dump and phy register dump in debugfs. Change-Id: Ib6e2f015d4fe682d25f1f61c3d2d40a69d64e794 Signed-off-by: Suraj Jaiswal --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 177 +++++++++++++++++- .../stmicro/stmmac/dwmac-qcom-ethqos.h | 18 +- 2 files changed, 193 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 924fc8ac2482..80fa7ba9f764 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -115,6 +114,7 @@ #define MICREL_LINK_UP_INTR_STATUS BIT(0) bool phy_intr_en; +void *ipc_emac_log_ctxt; struct emac_emb_smmu_cb_ctx emac_emb_smmu_ctx = {0}; struct qcom_ethqos *pethqos; @@ -1336,6 +1336,173 @@ static int ethqos_set_early_eth_param(struct stmmac_priv *priv, return ret; } +static ssize_t read_phy_reg_dump(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct qcom_ethqos *ethqos = file->private_data; + unsigned int len = 0, buf_len = 2000; + char *buf; + ssize_t ret_cnt; + int phydata = 0; + int i = 0; + + struct platform_device *pdev = ethqos->pdev; + struct net_device *dev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(dev); + + if (!ethqos || !dev->phydev) { + ETHQOSERR("NULL Pointer\n"); + return -EINVAL; + } + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, buf_len - len, + "\n************* PHY Reg dump *************\n"); + + for (i = 0; i < 32; i++) { + phydata = ethqos_mdio_read(priv, priv->plat->phy_addr, i); + len += scnprintf(buf + len, buf_len - len, + "MII Register (%#x) = %#x\n", + i, phydata); + } + + if (len > buf_len) { + ETHQOSERR("(len > buf_len) buffer not sufficient\n"); + len = buf_len; + } + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret_cnt; +} + +static ssize_t read_rgmii_reg_dump(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct qcom_ethqos *ethqos = file->private_data; + unsigned int len = 0, buf_len = 2000; + char *buf; + ssize_t ret_cnt; + int rgmii_data = 0; + struct platform_device *pdev = ethqos->pdev; + + struct net_device *dev = platform_get_drvdata(pdev); + + if (!ethqos || !dev->phydev) { + ETHQOSERR("NULL Pointer\n"); + return -EINVAL; + } + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, buf_len - len, + "\n************* RGMII Reg dump *************\n"); + rgmii_data = rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG); + len += scnprintf(buf + len, buf_len - len, + "RGMII_IO_MACRO_CONFIG Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); + len += scnprintf(buf + len, buf_len - len, + "SDCC_HC_REG_DLL_CONFIG Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, SDCC_HC_REG_DDR_CONFIG); + len += scnprintf(buf + len, buf_len - len, + "SDCC_HC_REG_DDR_CONFIG Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG2); + len += scnprintf(buf + len, buf_len - len, + "SDCC_HC_REG_DLL_CONFIG2 Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, SDC4_STATUS); + len += scnprintf(buf + len, buf_len - len, + "SDC4_STATUS Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, SDCC_USR_CTL); + len += scnprintf(buf + len, buf_len - len, + "SDCC_USR_CTL Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG2); + len += scnprintf(buf + len, buf_len - len, + "RGMII_IO_MACRO_CONFIG2 Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, RGMII_IO_MACRO_DEBUG1); + len += scnprintf(buf + len, buf_len - len, + "RGMII_IO_MACRO_DEBUG1 Register = %#x\n", + rgmii_data); + rgmii_data = rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG); + len += scnprintf(buf + len, buf_len - len, + "EMAC_SYSTEM_LOW_POWER_DEBUG Register = %#x\n", + rgmii_data); + + if (len > buf_len) { + ETHQOSERR("(len > buf_len) buffer not sufficient\n"); + len = buf_len; + } + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret_cnt; +} + +static const struct file_operations fops_phy_reg_dump = { + .read = read_phy_reg_dump, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_rgmii_reg_dump = { + .read = read_rgmii_reg_dump, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static int ethqos_create_debugfs(struct qcom_ethqos *ethqos) +{ + static struct dentry *phy_reg_dump; + static struct dentry *rgmii_reg_dump; + + if (!ethqos) { + ETHQOSERR("Null Param %s\n", __func__); + return -ENOMEM; + } + + ethqos->debugfs_dir = debugfs_create_dir("eth", NULL); + + if (!ethqos->debugfs_dir || IS_ERR(ethqos->debugfs_dir)) { + ETHQOSERR("Can't create debugfs dir\n"); + return -ENOMEM; + } + + phy_reg_dump = debugfs_create_file("phy_reg_dump", 0400, + ethqos->debugfs_dir, ethqos, + &fops_phy_reg_dump); + if (!phy_reg_dump || IS_ERR(phy_reg_dump)) { + ETHQOSERR("Can't create phy_dump %p\n", phy_reg_dump); + goto fail; + } + + rgmii_reg_dump = debugfs_create_file("rgmii_reg_dump", 0400, + ethqos->debugfs_dir, ethqos, + &fops_rgmii_reg_dump); + if (!rgmii_reg_dump || IS_ERR(rgmii_reg_dump)) { + ETHQOSERR("Can't create rgmii_dump %p\n", rgmii_reg_dump); + goto fail; + } + return 0; + +fail: + debugfs_remove_recursive(ethqos->debugfs_dir); + return -ENOMEM; +} + static int qcom_ethqos_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1354,6 +1521,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev) #ifdef CONFIG_MSM_BOOT_TIME_MARKER place_marker("M - Ethernet probe start"); #endif + + ipc_emac_log_ctxt = ipc_log_context_create(IPCLOG_STATE_PAGES, + "emac", 0); + if (!ipc_emac_log_ctxt) + ETHQOSERR("Error creating logging context for emac\n"); + else + ETHQOSDBG("IPC logging has been enabled for emac\n"); ret = stmmac_get_platform_resources(pdev, &stmmac_res); if (ret) return ret; @@ -1477,6 +1651,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) } pethqos = ethqos; + ethqos_create_debugfs(ethqos); ndev = dev_get_drvdata(ðqos->pdev->dev); priv = netdev_priv(ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h index 4c7ad48f5645..b3ef4ff72b65 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h @@ -5,6 +5,13 @@ #define _DWMAC_QCOM_ETHQOS_H //#include +#include + +extern void *ipc_emac_log_ctxt; + +#define IPCLOG_STATE_PAGES 50 +#define __FILENAME__ (strrchr(__FILE__, '/') ? \ + strrchr(__FILE__, '/') + 1 : __FILE__) #include #include @@ -22,7 +29,14 @@ #define ETHQOSDBG(fmt, args...) \ pr_debug(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define ETHQOSERR(fmt, args...) \ - pr_err(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) +do {\ + pr_err(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args);\ + if (ipc_emac_log_ctxt) { \ + ipc_log_string(ipc_emac_log_ctxt, \ + "%s: %s[%u]:[emac] ERROR:" fmt, __FILENAME__,\ + __func__, __LINE__, ## args); \ + } \ +} while (0) #define ETHQOSINFO(fmt, args...) \ pr_info(DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args) #define RGMII_IO_MACRO_CONFIG 0x0 @@ -181,6 +195,8 @@ struct qcom_ethqos { bool early_eth_enabled; /* Key Performance Indicators */ bool print_kpi; + + struct dentry *debugfs_dir; }; struct pps_cfg {