1253ac3a9SLuo bin // SPDX-License-Identifier: GPL-2.0-only
2253ac3a9SLuo bin /* Huawei HiNIC PCI Express Linux driver
3253ac3a9SLuo bin  * Copyright(c) 2017 Huawei Technologies Co., Ltd
4253ac3a9SLuo bin  */
5253ac3a9SLuo bin 
6253ac3a9SLuo bin #include <linux/debugfs.h>
7253ac3a9SLuo bin #include <linux/device.h>
8253ac3a9SLuo bin 
9253ac3a9SLuo bin #include "hinic_debugfs.h"
10253ac3a9SLuo bin 
11253ac3a9SLuo bin static struct dentry *hinic_dbgfs_root;
12253ac3a9SLuo bin 
13253ac3a9SLuo bin enum sq_dbg_info {
14253ac3a9SLuo bin 	GLB_SQ_ID,
15253ac3a9SLuo bin 	SQ_PI,
16253ac3a9SLuo bin 	SQ_CI,
17253ac3a9SLuo bin 	SQ_FI,
18253ac3a9SLuo bin 	SQ_MSIX_ENTRY,
19253ac3a9SLuo bin };
20253ac3a9SLuo bin 
21253ac3a9SLuo bin static char *sq_fields[] = {"glb_sq_id", "sq_pi", "sq_ci", "sq_fi", "sq_msix_entry"};
22253ac3a9SLuo bin 
hinic_dbg_get_sq_info(struct hinic_dev * nic_dev,struct hinic_sq * sq,int idx)23253ac3a9SLuo bin static u64 hinic_dbg_get_sq_info(struct hinic_dev *nic_dev, struct hinic_sq *sq, int idx)
24253ac3a9SLuo bin {
25253ac3a9SLuo bin 	struct hinic_wq *wq = sq->wq;
26253ac3a9SLuo bin 
27253ac3a9SLuo bin 	switch (idx) {
28253ac3a9SLuo bin 	case GLB_SQ_ID:
29253ac3a9SLuo bin 		return nic_dev->hwdev->func_to_io.global_qpn + sq->qid;
30253ac3a9SLuo bin 	case SQ_PI:
31253ac3a9SLuo bin 		return atomic_read(&wq->prod_idx) & wq->mask;
32253ac3a9SLuo bin 	case SQ_CI:
33253ac3a9SLuo bin 		return atomic_read(&wq->cons_idx) & wq->mask;
34253ac3a9SLuo bin 	case SQ_FI:
35253ac3a9SLuo bin 		return be16_to_cpu(*(__be16 *)(sq->hw_ci_addr)) & wq->mask;
36253ac3a9SLuo bin 	case SQ_MSIX_ENTRY:
37253ac3a9SLuo bin 		return sq->msix_entry;
38253ac3a9SLuo bin 	}
39253ac3a9SLuo bin 
40253ac3a9SLuo bin 	return 0;
41253ac3a9SLuo bin }
42253ac3a9SLuo bin 
43626f0603SLuo bin enum rq_dbg_info {
44626f0603SLuo bin 	GLB_RQ_ID,
45626f0603SLuo bin 	RQ_HW_PI,
46626f0603SLuo bin 	RQ_SW_CI,
47626f0603SLuo bin 	RQ_SW_PI,
48626f0603SLuo bin 	RQ_MSIX_ENTRY,
49626f0603SLuo bin };
50626f0603SLuo bin 
51626f0603SLuo bin static char *rq_fields[] = {"glb_rq_id", "rq_hw_pi", "rq_sw_ci", "rq_sw_pi", "rq_msix_entry"};
52626f0603SLuo bin 
hinic_dbg_get_rq_info(struct hinic_dev * nic_dev,struct hinic_rq * rq,int idx)53626f0603SLuo bin static u64 hinic_dbg_get_rq_info(struct hinic_dev *nic_dev, struct hinic_rq *rq, int idx)
54626f0603SLuo bin {
55626f0603SLuo bin 	struct hinic_wq *wq = rq->wq;
56626f0603SLuo bin 
57626f0603SLuo bin 	switch (idx) {
58626f0603SLuo bin 	case GLB_RQ_ID:
59626f0603SLuo bin 		return nic_dev->hwdev->func_to_io.global_qpn + rq->qid;
60626f0603SLuo bin 	case RQ_HW_PI:
61626f0603SLuo bin 		return be16_to_cpu(*(__be16 *)(rq->pi_virt_addr)) & wq->mask;
62626f0603SLuo bin 	case RQ_SW_CI:
63626f0603SLuo bin 		return atomic_read(&wq->cons_idx) & wq->mask;
64626f0603SLuo bin 	case RQ_SW_PI:
65626f0603SLuo bin 		return atomic_read(&wq->prod_idx) & wq->mask;
66626f0603SLuo bin 	case RQ_MSIX_ENTRY:
67626f0603SLuo bin 		return rq->msix_entry;
68626f0603SLuo bin 	}
69626f0603SLuo bin 
70626f0603SLuo bin 	return 0;
71626f0603SLuo bin }
72626f0603SLuo bin 
735215e162SLuo bin enum func_tbl_info {
745215e162SLuo bin 	VALID,
755215e162SLuo bin 	RX_MODE,
765215e162SLuo bin 	MTU,
775215e162SLuo bin 	RQ_DEPTH,
785215e162SLuo bin 	QUEUE_NUM,
795215e162SLuo bin };
805215e162SLuo bin 
815215e162SLuo bin static char *func_table_fields[] = {"valid", "rx_mode", "mtu", "rq_depth", "cfg_q_num"};
825215e162SLuo bin 
hinic_dbg_get_func_table(struct hinic_dev * nic_dev,int idx)835215e162SLuo bin static int hinic_dbg_get_func_table(struct hinic_dev *nic_dev, int idx)
845215e162SLuo bin {
855215e162SLuo bin 	struct tag_sml_funcfg_tbl *funcfg_table_elem;
865215e162SLuo bin 	struct hinic_cmd_lt_rd *read_data;
875215e162SLuo bin 	u16 out_size = sizeof(*read_data);
88e6765fe8SZhengchao Shao 	int ret = ~0;
895215e162SLuo bin 	int err;
905215e162SLuo bin 
915215e162SLuo bin 	read_data = kzalloc(sizeof(*read_data), GFP_KERNEL);
925215e162SLuo bin 	if (!read_data)
935215e162SLuo bin 		return ~0;
945215e162SLuo bin 
955215e162SLuo bin 	read_data->node = TBL_ID_FUNC_CFG_SM_NODE;
965215e162SLuo bin 	read_data->inst = TBL_ID_FUNC_CFG_SM_INST;
975215e162SLuo bin 	read_data->entry_size = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;
985215e162SLuo bin 	read_data->lt_index = HINIC_HWIF_FUNC_IDX(nic_dev->hwdev->hwif);
995215e162SLuo bin 	read_data->len = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;
1005215e162SLuo bin 
1015215e162SLuo bin 	err = hinic_port_msg_cmd(nic_dev->hwdev, HINIC_PORT_CMD_RD_LINE_TBL, read_data,
1025215e162SLuo bin 				 sizeof(*read_data), read_data, &out_size);
1035215e162SLuo bin 	if (err || out_size != sizeof(*read_data) || read_data->status) {
1045215e162SLuo bin 		netif_err(nic_dev, drv, nic_dev->netdev,
1055215e162SLuo bin 			  "Failed to get func table, err: %d, status: 0x%x, out size: 0x%x\n",
1065215e162SLuo bin 			  err, read_data->status, out_size);
1075215e162SLuo bin 		kfree(read_data);
1085215e162SLuo bin 		return ~0;
1095215e162SLuo bin 	}
1105215e162SLuo bin 
1115215e162SLuo bin 	funcfg_table_elem = (struct tag_sml_funcfg_tbl *)read_data->data;
1125215e162SLuo bin 
1135215e162SLuo bin 	switch (idx) {
1145215e162SLuo bin 	case VALID:
115e6765fe8SZhengchao Shao 		ret = funcfg_table_elem->dw0.bs.valid;
116e6765fe8SZhengchao Shao 		break;
1175215e162SLuo bin 	case RX_MODE:
118e6765fe8SZhengchao Shao 		ret = funcfg_table_elem->dw0.bs.nic_rx_mode;
119e6765fe8SZhengchao Shao 		break;
1205215e162SLuo bin 	case MTU:
121e6765fe8SZhengchao Shao 		ret = funcfg_table_elem->dw1.bs.mtu;
122e6765fe8SZhengchao Shao 		break;
1235215e162SLuo bin 	case RQ_DEPTH:
124e6765fe8SZhengchao Shao 		ret = funcfg_table_elem->dw13.bs.cfg_rq_depth;
125e6765fe8SZhengchao Shao 		break;
1265215e162SLuo bin 	case QUEUE_NUM:
127e6765fe8SZhengchao Shao 		ret = funcfg_table_elem->dw13.bs.cfg_q_num;
128e6765fe8SZhengchao Shao 		break;
1295215e162SLuo bin 	}
1305215e162SLuo bin 
1315215e162SLuo bin 	kfree(read_data);
1325215e162SLuo bin 
133e6765fe8SZhengchao Shao 	return ret;
1345215e162SLuo bin }
1355215e162SLuo bin 
hinic_dbg_cmd_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)136253ac3a9SLuo bin static ssize_t hinic_dbg_cmd_read(struct file *filp, char __user *buffer, size_t count,
137253ac3a9SLuo bin 				  loff_t *ppos)
138253ac3a9SLuo bin {
139253ac3a9SLuo bin 	struct hinic_debug_priv *dbg;
140253ac3a9SLuo bin 	char ret_buf[20];
141253ac3a9SLuo bin 	int *desc;
142253ac3a9SLuo bin 	u64 out;
143253ac3a9SLuo bin 	int ret;
144253ac3a9SLuo bin 
145253ac3a9SLuo bin 	desc = filp->private_data;
146253ac3a9SLuo bin 	dbg = container_of(desc, struct hinic_debug_priv, field_id[*desc]);
147253ac3a9SLuo bin 
148253ac3a9SLuo bin 	switch (dbg->type) {
149253ac3a9SLuo bin 	case HINIC_DBG_SQ_INFO:
150253ac3a9SLuo bin 		out = hinic_dbg_get_sq_info(dbg->dev, dbg->object, *desc);
151253ac3a9SLuo bin 		break;
152253ac3a9SLuo bin 
153626f0603SLuo bin 	case HINIC_DBG_RQ_INFO:
154626f0603SLuo bin 		out = hinic_dbg_get_rq_info(dbg->dev, dbg->object, *desc);
155626f0603SLuo bin 		break;
156626f0603SLuo bin 
1575215e162SLuo bin 	case HINIC_DBG_FUNC_TABLE:
1585215e162SLuo bin 		out = hinic_dbg_get_func_table(dbg->dev, *desc);
1595215e162SLuo bin 		break;
1605215e162SLuo bin 
161253ac3a9SLuo bin 	default:
162253ac3a9SLuo bin 		netif_warn(dbg->dev, drv, dbg->dev->netdev, "Invalid hinic debug cmd: %d\n",
163253ac3a9SLuo bin 			   dbg->type);
164253ac3a9SLuo bin 		return -EINVAL;
165253ac3a9SLuo bin 	}
166253ac3a9SLuo bin 
167253ac3a9SLuo bin 	ret = snprintf(ret_buf, sizeof(ret_buf), "0x%llx\n", out);
168253ac3a9SLuo bin 
169253ac3a9SLuo bin 	return simple_read_from_buffer(buffer, count, ppos, ret_buf, ret);
170253ac3a9SLuo bin }
171253ac3a9SLuo bin 
172253ac3a9SLuo bin static const struct file_operations hinic_dbg_cmd_fops = {
173253ac3a9SLuo bin 	.owner = THIS_MODULE,
174253ac3a9SLuo bin 	.open  = simple_open,
175253ac3a9SLuo bin 	.read  = hinic_dbg_cmd_read,
176253ac3a9SLuo bin };
177253ac3a9SLuo bin 
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)178253ac3a9SLuo bin static int create_dbg_files(struct hinic_dev *dev, enum hinic_dbg_type type, void *data,
179253ac3a9SLuo bin 			    struct dentry *root, struct hinic_debug_priv **dbg, char **field,
180253ac3a9SLuo bin 			    int nfile)
181253ac3a9SLuo bin {
182253ac3a9SLuo bin 	struct hinic_debug_priv *tmp;
183253ac3a9SLuo bin 	int i;
184253ac3a9SLuo bin 
185253ac3a9SLuo bin 	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
186253ac3a9SLuo bin 	if (!tmp)
187253ac3a9SLuo bin 		return -ENOMEM;
188253ac3a9SLuo bin 
189253ac3a9SLuo bin 	tmp->dev = dev;
190253ac3a9SLuo bin 	tmp->object = data;
191253ac3a9SLuo bin 	tmp->type = type;
192253ac3a9SLuo bin 	tmp->root = root;
193253ac3a9SLuo bin 
194253ac3a9SLuo bin 	for (i = 0; i < nfile; i++) {
195253ac3a9SLuo bin 		tmp->field_id[i] = i;
196253ac3a9SLuo bin 		debugfs_create_file(field[i], 0400, root, &tmp->field_id[i], &hinic_dbg_cmd_fops);
197253ac3a9SLuo bin 	}
198253ac3a9SLuo bin 
199253ac3a9SLuo bin 	*dbg = tmp;
200253ac3a9SLuo bin 
201253ac3a9SLuo bin 	return 0;
202253ac3a9SLuo bin }
203253ac3a9SLuo bin 
rem_dbg_files(struct hinic_debug_priv * dbg)204253ac3a9SLuo bin static void rem_dbg_files(struct hinic_debug_priv *dbg)
205253ac3a9SLuo bin {
2065215e162SLuo bin 	if (dbg->type != HINIC_DBG_FUNC_TABLE)
207253ac3a9SLuo bin 		debugfs_remove_recursive(dbg->root);
2085215e162SLuo bin 
209253ac3a9SLuo bin 	kfree(dbg);
210253ac3a9SLuo bin }
211253ac3a9SLuo bin 
hinic_sq_debug_add(struct hinic_dev * dev,u16 sq_id)212253ac3a9SLuo bin int hinic_sq_debug_add(struct hinic_dev *dev, u16 sq_id)
213253ac3a9SLuo bin {
214253ac3a9SLuo bin 	struct hinic_sq *sq;
215253ac3a9SLuo bin 	struct dentry *root;
216253ac3a9SLuo bin 	char sub_dir[16];
217253ac3a9SLuo bin 
218253ac3a9SLuo bin 	sq = dev->txqs[sq_id].sq;
219253ac3a9SLuo bin 
220253ac3a9SLuo bin 	sprintf(sub_dir, "0x%x", sq_id);
221253ac3a9SLuo bin 
222253ac3a9SLuo bin 	root = debugfs_create_dir(sub_dir, dev->sq_dbgfs);
223253ac3a9SLuo bin 
224253ac3a9SLuo bin 	return create_dbg_files(dev, HINIC_DBG_SQ_INFO, sq, root, &sq->dbg, sq_fields,
225253ac3a9SLuo bin 				ARRAY_SIZE(sq_fields));
226253ac3a9SLuo bin }
227253ac3a9SLuo bin 
hinic_sq_debug_rem(struct hinic_sq * sq)228253ac3a9SLuo bin void hinic_sq_debug_rem(struct hinic_sq *sq)
229253ac3a9SLuo bin {
230253ac3a9SLuo bin 	if (sq->dbg)
231253ac3a9SLuo bin 		rem_dbg_files(sq->dbg);
232253ac3a9SLuo bin }
233253ac3a9SLuo bin 
hinic_rq_debug_add(struct hinic_dev * dev,u16 rq_id)234626f0603SLuo bin int hinic_rq_debug_add(struct hinic_dev *dev, u16 rq_id)
235626f0603SLuo bin {
236626f0603SLuo bin 	struct hinic_rq *rq;
237626f0603SLuo bin 	struct dentry *root;
238626f0603SLuo bin 	char sub_dir[16];
239626f0603SLuo bin 
240626f0603SLuo bin 	rq = dev->rxqs[rq_id].rq;
241626f0603SLuo bin 
242626f0603SLuo bin 	sprintf(sub_dir, "0x%x", rq_id);
243626f0603SLuo bin 
244626f0603SLuo bin 	root = debugfs_create_dir(sub_dir, dev->rq_dbgfs);
245626f0603SLuo bin 
246626f0603SLuo bin 	return create_dbg_files(dev, HINIC_DBG_RQ_INFO, rq, root, &rq->dbg, rq_fields,
247626f0603SLuo bin 				ARRAY_SIZE(rq_fields));
248626f0603SLuo bin }
249626f0603SLuo bin 
hinic_rq_debug_rem(struct hinic_rq * rq)250626f0603SLuo bin void hinic_rq_debug_rem(struct hinic_rq *rq)
251626f0603SLuo bin {
252626f0603SLuo bin 	if (rq->dbg)
253626f0603SLuo bin 		rem_dbg_files(rq->dbg);
254626f0603SLuo bin }
255626f0603SLuo bin 
hinic_func_table_debug_add(struct hinic_dev * dev)2565215e162SLuo bin int hinic_func_table_debug_add(struct hinic_dev *dev)
2575215e162SLuo bin {
2585215e162SLuo bin 	if (HINIC_IS_VF(dev->hwdev->hwif))
2595215e162SLuo bin 		return 0;
2605215e162SLuo bin 
2615215e162SLuo bin 	return create_dbg_files(dev, HINIC_DBG_FUNC_TABLE, dev, dev->func_tbl_dbgfs, &dev->dbg,
2625215e162SLuo bin 				func_table_fields, ARRAY_SIZE(func_table_fields));
2635215e162SLuo bin }
2645215e162SLuo bin 
hinic_func_table_debug_rem(struct hinic_dev * dev)2655215e162SLuo bin void hinic_func_table_debug_rem(struct hinic_dev *dev)
2665215e162SLuo bin {
2675215e162SLuo bin 	if (!HINIC_IS_VF(dev->hwdev->hwif) && dev->dbg)
2685215e162SLuo bin 		rem_dbg_files(dev->dbg);
2695215e162SLuo bin }
2705215e162SLuo bin 
hinic_sq_dbgfs_init(struct hinic_dev * nic_dev)271253ac3a9SLuo bin void hinic_sq_dbgfs_init(struct hinic_dev *nic_dev)
272253ac3a9SLuo bin {
273253ac3a9SLuo bin 	nic_dev->sq_dbgfs = debugfs_create_dir("SQs", nic_dev->dbgfs_root);
274253ac3a9SLuo bin }
275253ac3a9SLuo bin 
hinic_sq_dbgfs_uninit(struct hinic_dev * nic_dev)276253ac3a9SLuo bin void hinic_sq_dbgfs_uninit(struct hinic_dev *nic_dev)
277253ac3a9SLuo bin {
278253ac3a9SLuo bin 	debugfs_remove_recursive(nic_dev->sq_dbgfs);
279253ac3a9SLuo bin }
280253ac3a9SLuo bin 
hinic_rq_dbgfs_init(struct hinic_dev * nic_dev)281626f0603SLuo bin void hinic_rq_dbgfs_init(struct hinic_dev *nic_dev)
282626f0603SLuo bin {
283626f0603SLuo bin 	nic_dev->rq_dbgfs = debugfs_create_dir("RQs", nic_dev->dbgfs_root);
284626f0603SLuo bin }
285626f0603SLuo bin 
hinic_rq_dbgfs_uninit(struct hinic_dev * nic_dev)286626f0603SLuo bin void hinic_rq_dbgfs_uninit(struct hinic_dev *nic_dev)
287626f0603SLuo bin {
288626f0603SLuo bin 	debugfs_remove_recursive(nic_dev->rq_dbgfs);
289626f0603SLuo bin }
290626f0603SLuo bin 
hinic_func_tbl_dbgfs_init(struct hinic_dev * nic_dev)2915215e162SLuo bin void hinic_func_tbl_dbgfs_init(struct hinic_dev *nic_dev)
2925215e162SLuo bin {
2935215e162SLuo bin 	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
2945215e162SLuo bin 		nic_dev->func_tbl_dbgfs = debugfs_create_dir("func_table", nic_dev->dbgfs_root);
2955215e162SLuo bin }
2965215e162SLuo bin 
hinic_func_tbl_dbgfs_uninit(struct hinic_dev * nic_dev)2975215e162SLuo bin void hinic_func_tbl_dbgfs_uninit(struct hinic_dev *nic_dev)
2985215e162SLuo bin {
2995215e162SLuo bin 	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
3005215e162SLuo bin 		debugfs_remove_recursive(nic_dev->func_tbl_dbgfs);
3015215e162SLuo bin }
3025215e162SLuo bin 
hinic_dbg_init(struct hinic_dev * nic_dev)303253ac3a9SLuo bin void hinic_dbg_init(struct hinic_dev *nic_dev)
304253ac3a9SLuo bin {
305253ac3a9SLuo bin 	nic_dev->dbgfs_root = debugfs_create_dir(pci_name(nic_dev->hwdev->hwif->pdev),
306253ac3a9SLuo bin 						 hinic_dbgfs_root);
307253ac3a9SLuo bin }
308253ac3a9SLuo bin 
hinic_dbg_uninit(struct hinic_dev * nic_dev)309253ac3a9SLuo bin void hinic_dbg_uninit(struct hinic_dev *nic_dev)
310253ac3a9SLuo bin {
311253ac3a9SLuo bin 	debugfs_remove_recursive(nic_dev->dbgfs_root);
312253ac3a9SLuo bin 	nic_dev->dbgfs_root = NULL;
313253ac3a9SLuo bin }
314253ac3a9SLuo bin 
hinic_dbg_register_debugfs(const char * debugfs_dir_name)315253ac3a9SLuo bin void hinic_dbg_register_debugfs(const char *debugfs_dir_name)
316253ac3a9SLuo bin {
317253ac3a9SLuo bin 	hinic_dbgfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
318253ac3a9SLuo bin }
319253ac3a9SLuo bin 
hinic_dbg_unregister_debugfs(void)320253ac3a9SLuo bin void hinic_dbg_unregister_debugfs(void)
321253ac3a9SLuo bin {
322253ac3a9SLuo bin 	debugfs_remove_recursive(hinic_dbgfs_root);
323253ac3a9SLuo bin 	hinic_dbgfs_root = NULL;
324253ac3a9SLuo bin }
325