From 253ac3a97921b89171069e8f12fd89b6bf1e66c5 Mon Sep 17 00:00:00 2001 From: Luo bin Date: Fri, 28 Aug 2020 11:37:46 +0800 Subject: [PATCH] hinic: add support to query sq info add debugfs node for querying sq info, for example: cat /sys/kernel/debug/hinic/0000:15:00.0/SQs/0x0/sq_pi Signed-off-by: Luo bin Signed-off-by: David S. Miller --- drivers/net/ethernet/huawei/hinic/Makefile | 3 +- .../net/ethernet/huawei/hinic/hinic_debugfs.c | 162 ++++++++++++++++++ .../net/ethernet/huawei/hinic/hinic_debugfs.h | 27 +++ drivers/net/ethernet/huawei/hinic/hinic_dev.h | 15 ++ .../net/ethernet/huawei/hinic/hinic_hw_dev.c | 1 + .../net/ethernet/huawei/hinic/hinic_hw_io.c | 1 + .../net/ethernet/huawei/hinic/hinic_hw_io.h | 1 + .../net/ethernet/huawei/hinic/hinic_hw_qp.h | 3 + .../net/ethernet/huawei/hinic/hinic_main.c | 45 ++++- 9 files changed, 254 insertions(+), 4 deletions(-) create mode 100644 drivers/net/ethernet/huawei/hinic/hinic_debugfs.c create mode 100644 drivers/net/ethernet/huawei/hinic/hinic_debugfs.h diff --git a/drivers/net/ethernet/huawei/hinic/Makefile b/drivers/net/ethernet/huawei/hinic/Makefile index 67b59d0ba769..2f89119c9b69 100644 --- a/drivers/net/ethernet/huawei/hinic/Makefile +++ b/drivers/net/ethernet/huawei/hinic/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_HINIC) += hinic.o hinic-y := hinic_main.o hinic_tx.o hinic_rx.o hinic_port.o hinic_hw_dev.o \ hinic_hw_io.o hinic_hw_qp.o hinic_hw_cmdq.o hinic_hw_wq.o \ hinic_hw_mgmt.o hinic_hw_api_cmd.o hinic_hw_eqs.o hinic_hw_if.o \ - hinic_common.o hinic_ethtool.o hinic_devlink.o hinic_hw_mbox.o hinic_sriov.o + hinic_common.o hinic_ethtool.o hinic_devlink.o hinic_hw_mbox.o \ + hinic_sriov.o hinic_debugfs.o diff --git a/drivers/net/ethernet/huawei/hinic/hinic_debugfs.c b/drivers/net/ethernet/huawei/hinic/hinic_debugfs.c new file mode 100644 index 000000000000..2a1050cb400e --- /dev/null +++ b/drivers/net/ethernet/huawei/hinic/hinic_debugfs.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Huawei HiNIC PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#include +#include + +#include "hinic_debugfs.h" + +static struct dentry *hinic_dbgfs_root; + +enum sq_dbg_info { + GLB_SQ_ID, + SQ_PI, + SQ_CI, + SQ_FI, + SQ_MSIX_ENTRY, +}; + +static char *sq_fields[] = {"glb_sq_id", "sq_pi", "sq_ci", "sq_fi", "sq_msix_entry"}; + +static u64 hinic_dbg_get_sq_info(struct hinic_dev *nic_dev, struct hinic_sq *sq, int idx) +{ + struct hinic_wq *wq = sq->wq; + + switch (idx) { + case GLB_SQ_ID: + return nic_dev->hwdev->func_to_io.global_qpn + sq->qid; + case SQ_PI: + return atomic_read(&wq->prod_idx) & wq->mask; + case SQ_CI: + return atomic_read(&wq->cons_idx) & wq->mask; + case SQ_FI: + return be16_to_cpu(*(__be16 *)(sq->hw_ci_addr)) & wq->mask; + case SQ_MSIX_ENTRY: + return sq->msix_entry; + } + + return 0; +} + +static ssize_t hinic_dbg_cmd_read(struct file *filp, char __user *buffer, size_t count, + loff_t *ppos) +{ + struct hinic_debug_priv *dbg; + char ret_buf[20]; + int *desc; + u64 out; + int ret; + + desc = filp->private_data; + dbg = container_of(desc, struct hinic_debug_priv, field_id[*desc]); + + switch (dbg->type) { + case HINIC_DBG_SQ_INFO: + out = hinic_dbg_get_sq_info(dbg->dev, dbg->object, *desc); + break; + + default: + netif_warn(dbg->dev, drv, dbg->dev->netdev, "Invalid hinic debug cmd: %d\n", + dbg->type); + return -EINVAL; + } + + ret = snprintf(ret_buf, sizeof(ret_buf), "0x%llx\n", out); + + return simple_read_from_buffer(buffer, count, ppos, ret_buf, ret); +} + +static const struct file_operations hinic_dbg_cmd_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = hinic_dbg_cmd_read, +}; + +static int create_dbg_files(struct hinic_dev *dev, enum hinic_dbg_type type, void *data, + struct dentry *root, struct hinic_debug_priv **dbg, char **field, + int nfile) +{ + struct hinic_debug_priv *tmp; + int i; + + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + tmp->dev = dev; + tmp->object = data; + tmp->type = type; + tmp->root = root; + + for (i = 0; i < nfile; i++) { + tmp->field_id[i] = i; + debugfs_create_file(field[i], 0400, root, &tmp->field_id[i], &hinic_dbg_cmd_fops); + } + + *dbg = tmp; + + return 0; +} + +static void rem_dbg_files(struct hinic_debug_priv *dbg) +{ + debugfs_remove_recursive(dbg->root); + kfree(dbg); +} + +int hinic_sq_debug_add(struct hinic_dev *dev, u16 sq_id) +{ + struct hinic_sq *sq; + struct dentry *root; + char sub_dir[16]; + + sq = dev->txqs[sq_id].sq; + + sprintf(sub_dir, "0x%x", sq_id); + + root = debugfs_create_dir(sub_dir, dev->sq_dbgfs); + + return create_dbg_files(dev, HINIC_DBG_SQ_INFO, sq, root, &sq->dbg, sq_fields, + ARRAY_SIZE(sq_fields)); +} + +void hinic_sq_debug_rem(struct hinic_sq *sq) +{ + if (sq->dbg) + rem_dbg_files(sq->dbg); +} + +void hinic_sq_dbgfs_init(struct hinic_dev *nic_dev) +{ + nic_dev->sq_dbgfs = debugfs_create_dir("SQs", nic_dev->dbgfs_root); +} + +void hinic_sq_dbgfs_uninit(struct hinic_dev *nic_dev) +{ + debugfs_remove_recursive(nic_dev->sq_dbgfs); +} + +void hinic_dbg_init(struct hinic_dev *nic_dev) +{ + nic_dev->dbgfs_root = debugfs_create_dir(pci_name(nic_dev->hwdev->hwif->pdev), + hinic_dbgfs_root); +} + +void hinic_dbg_uninit(struct hinic_dev *nic_dev) +{ + debugfs_remove_recursive(nic_dev->dbgfs_root); + nic_dev->dbgfs_root = NULL; +} + +void hinic_dbg_register_debugfs(const char *debugfs_dir_name) +{ + hinic_dbgfs_root = debugfs_create_dir(debugfs_dir_name, NULL); +} + +void hinic_dbg_unregister_debugfs(void) +{ + debugfs_remove_recursive(hinic_dbgfs_root); + hinic_dbgfs_root = NULL; +} diff --git a/drivers/net/ethernet/huawei/hinic/hinic_debugfs.h b/drivers/net/ethernet/huawei/hinic/hinic_debugfs.h new file mode 100644 index 000000000000..45fb3b40f487 --- /dev/null +++ b/drivers/net/ethernet/huawei/hinic/hinic_debugfs.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Huawei HiNIC PCI Express Linux driver + * Copyright(c) 2017 Huawei Technologies Co., Ltd + */ + +#ifndef HINIC_DEBUGFS_H +#define HINIC_DEBUGFS_H + +#include "hinic_dev.h" + +int hinic_sq_debug_add(struct hinic_dev *dev, u16 sq_id); + +void hinic_sq_debug_rem(struct hinic_sq *sq); + +void hinic_sq_dbgfs_init(struct hinic_dev *nic_dev); + +void hinic_sq_dbgfs_uninit(struct hinic_dev *nic_dev); + +void hinic_dbg_init(struct hinic_dev *nic_dev); + +void hinic_dbg_uninit(struct hinic_dev *nic_dev); + +void hinic_dbg_register_debugfs(const char *debugfs_dir_name); + +void hinic_dbg_unregister_debugfs(void); + +#endif diff --git a/drivers/net/ethernet/huawei/hinic/hinic_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_dev.h index 0a1e20edf7cf..95d9548014ac 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_dev.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_dev.h @@ -58,6 +58,18 @@ struct hinic_intr_coal_info { u8 resend_timer_cfg; }; +enum hinic_dbg_type { + HINIC_DBG_SQ_INFO, +}; + +struct hinic_debug_priv { + struct hinic_dev *dev; + void *object; + enum hinic_dbg_type type; + struct dentry *root; + int field_id[64]; +}; + struct hinic_dev { struct net_device *netdev; struct hinic_hwdev *hwdev; @@ -97,6 +109,9 @@ struct hinic_dev { int lb_test_rx_idx; int lb_pkt_len; u8 *lb_test_rx_buf; + + struct dentry *dbgfs_root; + struct dentry *sq_dbgfs; struct devlink *devlink; bool cable_unplugged; bool module_unrecognized; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c index 0c737765d113..239685152f6e 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c @@ -465,6 +465,7 @@ int hinic_hwdev_ifup(struct hinic_hwdev *hwdev, u16 sq_depth, u16 rq_depth) func_to_io->hwdev = hwdev; func_to_io->sq_depth = sq_depth; func_to_io->rq_depth = rq_depth; + func_to_io->global_qpn = base_qpn; err = hinic_io_init(func_to_io, hwif, nic_cap->max_qps, num_ceqs, ceq_msix_entries); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c index 3e3fa742e476..39a38edb89d6 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c @@ -305,6 +305,7 @@ static int init_qp(struct hinic_func_to_io *func_to_io, func_to_io->sq_db[q_id] = db_base; + qp->sq.qid = q_id; err = hinic_init_sq(&qp->sq, hwif, &func_to_io->sq_wq[q_id], sq_msix_entry, CI_ADDR(func_to_io->ci_addr_base, q_id), diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.h index ee6d60762d84..52159a90278a 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.h @@ -59,6 +59,7 @@ struct hinic_nic_cfg { struct hinic_func_to_io { struct hinic_hwif *hwif; struct hinic_hwdev *hwdev; + u16 global_qpn; struct hinic_ceqs ceqs; struct hinic_wqs wqs; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h index ca3e2d060284..936605cec4ab 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h @@ -81,6 +81,8 @@ struct hinic_sq { struct hinic_wq *wq; + u16 qid; + u32 irq; u16 msix_entry; @@ -90,6 +92,7 @@ struct hinic_sq { void __iomem *db_base; struct sk_buff **saved_skb; + struct hinic_debug_priv *dbg; }; struct hinic_rq { diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c index 501056fd32ee..aad1e5e1bfbe 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c @@ -24,6 +24,7 @@ #include #include +#include "hinic_debugfs.h" #include "hinic_hw_qp.h" #include "hinic_hw_dev.h" #include "hinic_devlink.h" @@ -153,6 +154,8 @@ static int create_txqs(struct hinic_dev *nic_dev) if (!nic_dev->txqs) return -ENOMEM; + hinic_sq_dbgfs_init(nic_dev); + for (i = 0; i < num_txqs; i++) { struct hinic_sq *sq = hinic_hwdev_get_sq(nic_dev->hwdev, i); @@ -162,13 +165,27 @@ static int create_txqs(struct hinic_dev *nic_dev) "Failed to init Txq\n"); goto err_init_txq; } + + err = hinic_sq_debug_add(nic_dev, i); + if (err) { + netif_err(nic_dev, drv, netdev, + "Failed to add SQ%d debug\n", i); + goto err_add_sq_dbg; + } + } return 0; +err_add_sq_dbg: + hinic_clean_txq(&nic_dev->txqs[i]); err_init_txq: - for (j = 0; j < i; j++) + for (j = 0; j < i; j++) { + hinic_sq_debug_rem(nic_dev->txqs[j].sq); hinic_clean_txq(&nic_dev->txqs[j]); + } + + hinic_sq_dbgfs_uninit(nic_dev); devm_kfree(&netdev->dev, nic_dev->txqs); return err; @@ -186,8 +203,12 @@ static void free_txqs(struct hinic_dev *nic_dev) if (!nic_dev->txqs) return; - for (i = 0; i < num_txqs; i++) + for (i = 0; i < num_txqs; i++) { + hinic_sq_debug_rem(nic_dev->txqs[i].sq); hinic_clean_txq(&nic_dev->txqs[i]); + } + + hinic_sq_dbgfs_uninit(nic_dev); devm_kfree(&netdev->dev, nic_dev->txqs); nic_dev->txqs = NULL; @@ -1260,6 +1281,8 @@ static int nic_dev_init(struct pci_dev *pdev) goto err_init_intr; } + hinic_dbg_init(nic_dev); + err = register_netdev(netdev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); @@ -1269,6 +1292,7 @@ static int nic_dev_init(struct pci_dev *pdev) return 0; err_reg_netdev: + hinic_dbg_uninit(nic_dev); hinic_free_intr_coalesce(nic_dev); err_init_intr: err_set_pfc: @@ -1391,6 +1415,8 @@ static void hinic_remove(struct pci_dev *pdev) unregister_netdev(netdev); + hinic_dbg_uninit(nic_dev); + hinic_free_intr_coalesce(nic_dev); hinic_port_del_mac(nic_dev, netdev->dev_addr, 0); @@ -1445,4 +1471,17 @@ static struct pci_driver hinic_driver = { .sriov_configure = hinic_pci_sriov_configure, }; -module_pci_driver(hinic_driver); +static int __init hinic_module_init(void) +{ + hinic_dbg_register_debugfs(HINIC_DRV_NAME); + return pci_register_driver(&hinic_driver); +} + +static void __exit hinic_module_exit(void) +{ + pci_unregister_driver(&hinic_driver); + hinic_dbg_unregister_debugfs(); +} + +module_init(hinic_module_init); +module_exit(hinic_module_exit);