Commit 3b44c793 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'hinic-add-debugfs-support'



Luo bin says:

====================
hinic: add debugfs support

add debugfs node for querying sq/rq info and function table
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c30a3c95 5215e162
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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
+318 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Huawei HiNIC PCI Express Linux driver
 * Copyright(c) 2017 Huawei Technologies Co., Ltd
 */

#include <linux/debugfs.h>
#include <linux/device.h>

#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;
}

enum rq_dbg_info {
	GLB_RQ_ID,
	RQ_HW_PI,
	RQ_SW_CI,
	RQ_SW_PI,
	RQ_MSIX_ENTRY,
};

static char *rq_fields[] = {"glb_rq_id", "rq_hw_pi", "rq_sw_ci", "rq_sw_pi", "rq_msix_entry"};

static u64 hinic_dbg_get_rq_info(struct hinic_dev *nic_dev, struct hinic_rq *rq, int idx)
{
	struct hinic_wq *wq = rq->wq;

	switch (idx) {
	case GLB_RQ_ID:
		return nic_dev->hwdev->func_to_io.global_qpn + rq->qid;
	case RQ_HW_PI:
		return be16_to_cpu(*(__be16 *)(rq->pi_virt_addr)) & wq->mask;
	case RQ_SW_CI:
		return atomic_read(&wq->cons_idx) & wq->mask;
	case RQ_SW_PI:
		return atomic_read(&wq->prod_idx) & wq->mask;
	case RQ_MSIX_ENTRY:
		return rq->msix_entry;
	}

	return 0;
}

enum func_tbl_info {
	VALID,
	RX_MODE,
	MTU,
	RQ_DEPTH,
	QUEUE_NUM,
};

static char *func_table_fields[] = {"valid", "rx_mode", "mtu", "rq_depth", "cfg_q_num"};

static int hinic_dbg_get_func_table(struct hinic_dev *nic_dev, int idx)
{
	struct tag_sml_funcfg_tbl *funcfg_table_elem;
	struct hinic_cmd_lt_rd *read_data;
	u16 out_size = sizeof(*read_data);
	int err;

	read_data = kzalloc(sizeof(*read_data), GFP_KERNEL);
	if (!read_data)
		return ~0;

	read_data->node = TBL_ID_FUNC_CFG_SM_NODE;
	read_data->inst = TBL_ID_FUNC_CFG_SM_INST;
	read_data->entry_size = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;
	read_data->lt_index = HINIC_HWIF_FUNC_IDX(nic_dev->hwdev->hwif);
	read_data->len = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;

	err = hinic_port_msg_cmd(nic_dev->hwdev, HINIC_PORT_CMD_RD_LINE_TBL, read_data,
				 sizeof(*read_data), read_data, &out_size);
	if (err || out_size != sizeof(*read_data) || read_data->status) {
		netif_err(nic_dev, drv, nic_dev->netdev,
			  "Failed to get func table, err: %d, status: 0x%x, out size: 0x%x\n",
			  err, read_data->status, out_size);
		kfree(read_data);
		return ~0;
	}

	funcfg_table_elem = (struct tag_sml_funcfg_tbl *)read_data->data;

	switch (idx) {
	case VALID:
		return funcfg_table_elem->dw0.bs.valid;
	case RX_MODE:
		return funcfg_table_elem->dw0.bs.nic_rx_mode;
	case MTU:
		return funcfg_table_elem->dw1.bs.mtu;
	case RQ_DEPTH:
		return funcfg_table_elem->dw13.bs.cfg_rq_depth;
	case QUEUE_NUM:
		return funcfg_table_elem->dw13.bs.cfg_q_num;
	}

	kfree(read_data);

	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;

	case HINIC_DBG_RQ_INFO:
		out = hinic_dbg_get_rq_info(dbg->dev, dbg->object, *desc);
		break;

	case HINIC_DBG_FUNC_TABLE:
		out = hinic_dbg_get_func_table(dbg->dev, *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)
{
	if (dbg->type != HINIC_DBG_FUNC_TABLE)
		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);
}

int hinic_rq_debug_add(struct hinic_dev *dev, u16 rq_id)
{
	struct hinic_rq *rq;
	struct dentry *root;
	char sub_dir[16];

	rq = dev->rxqs[rq_id].rq;

	sprintf(sub_dir, "0x%x", rq_id);

	root = debugfs_create_dir(sub_dir, dev->rq_dbgfs);

	return create_dbg_files(dev, HINIC_DBG_RQ_INFO, rq, root, &rq->dbg, rq_fields,
				ARRAY_SIZE(rq_fields));
}

void hinic_rq_debug_rem(struct hinic_rq *rq)
{
	if (rq->dbg)
		rem_dbg_files(rq->dbg);
}

int hinic_func_table_debug_add(struct hinic_dev *dev)
{
	if (HINIC_IS_VF(dev->hwdev->hwif))
		return 0;

	return create_dbg_files(dev, HINIC_DBG_FUNC_TABLE, dev, dev->func_tbl_dbgfs, &dev->dbg,
				func_table_fields, ARRAY_SIZE(func_table_fields));
}

void hinic_func_table_debug_rem(struct hinic_dev *dev)
{
	if (!HINIC_IS_VF(dev->hwdev->hwif) && dev->dbg)
		rem_dbg_files(dev->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_rq_dbgfs_init(struct hinic_dev *nic_dev)
{
	nic_dev->rq_dbgfs = debugfs_create_dir("RQs", nic_dev->dbgfs_root);
}

void hinic_rq_dbgfs_uninit(struct hinic_dev *nic_dev)
{
	debugfs_remove_recursive(nic_dev->rq_dbgfs);
}

void hinic_func_tbl_dbgfs_init(struct hinic_dev *nic_dev)
{
	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
		nic_dev->func_tbl_dbgfs = debugfs_create_dir("func_table", nic_dev->dbgfs_root);
}

void hinic_func_tbl_dbgfs_uninit(struct hinic_dev *nic_dev)
{
	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
		debugfs_remove_recursive(nic_dev->func_tbl_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;
}
+114 −0
Original line number Diff line number Diff line
/* 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"

#define    TBL_ID_FUNC_CFG_SM_NODE                      11
#define    TBL_ID_FUNC_CFG_SM_INST                      1

#define HINIC_FUNCTION_CONFIGURE_TABLE_SIZE             64
#define HINIC_FUNCTION_CONFIGURE_TABLE			1

struct hinic_cmd_lt_rd {
	u8	status;
	u8	version;
	u8	rsvd0[6];

	unsigned char node;
	unsigned char inst;
	unsigned char entry_size;
	unsigned char rsvd;
	unsigned int lt_index;
	unsigned int offset;
	unsigned int len;
	unsigned char data[100];
};

struct tag_sml_funcfg_tbl {
	union {
		struct {
			u32 rsvd0            :8;
			u32 nic_rx_mode      :5;
			u32 rsvd1            :18;
			u32 valid            :1;
		} bs;

		u32 value;
	} dw0;

	union {
		struct {
			u32 vlan_id             :12;
			u32 vlan_mode           :3;
			u32 fast_recycled_mode  :1;
			u32 mtu                 :16;
		} bs;

		u32 value;
	} dw1;

	u32 dw2;
	u32 dw3;
	u32 dw4;
	u32 dw5;
	u32 dw6;
	u32 dw7;
	u32 dw8;
	u32 dw9;
	u32 dw10;
	u32 dw11;
	u32 dw12;

	union {
		struct {
			u32 rsvd2               :15;
			u32 cfg_q_num           :9;
			u32 cfg_rq_depth        :6;
			u32 vhd_type            :2;
		} bs;

		u32 value;
	} dw13;

	u32 dw14;
	u32 dw15;
};

int hinic_sq_debug_add(struct hinic_dev *dev, u16 sq_id);

void hinic_sq_debug_rem(struct hinic_sq *sq);

int hinic_rq_debug_add(struct hinic_dev *dev, u16 rq_id);

void hinic_rq_debug_rem(struct hinic_rq *rq);

int hinic_func_table_debug_add(struct hinic_dev *dev);

void hinic_func_table_debug_rem(struct hinic_dev *dev);

void hinic_sq_dbgfs_init(struct hinic_dev *nic_dev);

void hinic_sq_dbgfs_uninit(struct hinic_dev *nic_dev);

void hinic_rq_dbgfs_init(struct hinic_dev *nic_dev);

void hinic_rq_dbgfs_uninit(struct hinic_dev *nic_dev);

void hinic_func_tbl_dbgfs_init(struct hinic_dev *nic_dev);

void hinic_func_tbl_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
+20 −0
Original line number Diff line number Diff line
@@ -58,6 +58,20 @@ struct hinic_intr_coal_info {
	u8	resend_timer_cfg;
};

enum hinic_dbg_type {
	HINIC_DBG_SQ_INFO,
	HINIC_DBG_RQ_INFO,
	HINIC_DBG_FUNC_TABLE,
};

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 +111,12 @@ 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 dentry			*rq_dbgfs;
	struct dentry			*func_tbl_dbgfs;
	struct hinic_debug_priv		*dbg;
	struct devlink			*devlink;
	bool				cable_unplugged;
	bool				module_unrecognized;
+1 −0
Original line number Diff line number Diff line
@@ -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);
Loading