1// SPDX-License-Identifier: GPL-2.0-only
2/* Huawei HiNIC PCI Express Linux driver
3 * Copyright(c) 2017 Huawei Technologies Co., Ltd
4 */
5
6#include <linux/debugfs.h>
7#include <linux/device.h>
8
9#include "hinic_debugfs.h"
10
11static struct dentry *hinic_dbgfs_root;
12
13enum sq_dbg_info {
14	GLB_SQ_ID,
15	SQ_PI,
16	SQ_CI,
17	SQ_FI,
18	SQ_MSIX_ENTRY,
19};
20
21static char *sq_fields[] = {"glb_sq_id", "sq_pi", "sq_ci", "sq_fi", "sq_msix_entry"};
22
23static u64 hinic_dbg_get_sq_info(struct hinic_dev *nic_dev, struct hinic_sq *sq, int idx)
24{
25	struct hinic_wq *wq = sq->wq;
26
27	switch (idx) {
28	case GLB_SQ_ID:
29		return nic_dev->hwdev->func_to_io.global_qpn + sq->qid;
30	case SQ_PI:
31		return atomic_read(&wq->prod_idx) & wq->mask;
32	case SQ_CI:
33		return atomic_read(&wq->cons_idx) & wq->mask;
34	case SQ_FI:
35		return be16_to_cpu(*(__be16 *)(sq->hw_ci_addr)) & wq->mask;
36	case SQ_MSIX_ENTRY:
37		return sq->msix_entry;
38	}
39
40	return 0;
41}
42
43enum rq_dbg_info {
44	GLB_RQ_ID,
45	RQ_HW_PI,
46	RQ_SW_CI,
47	RQ_SW_PI,
48	RQ_MSIX_ENTRY,
49};
50
51static char *rq_fields[] = {"glb_rq_id", "rq_hw_pi", "rq_sw_ci", "rq_sw_pi", "rq_msix_entry"};
52
53static u64 hinic_dbg_get_rq_info(struct hinic_dev *nic_dev, struct hinic_rq *rq, int idx)
54{
55	struct hinic_wq *wq = rq->wq;
56
57	switch (idx) {
58	case GLB_RQ_ID:
59		return nic_dev->hwdev->func_to_io.global_qpn + rq->qid;
60	case RQ_HW_PI:
61		return be16_to_cpu(*(__be16 *)(rq->pi_virt_addr)) & wq->mask;
62	case RQ_SW_CI:
63		return atomic_read(&wq->cons_idx) & wq->mask;
64	case RQ_SW_PI:
65		return atomic_read(&wq->prod_idx) & wq->mask;
66	case RQ_MSIX_ENTRY:
67		return rq->msix_entry;
68	}
69
70	return 0;
71}
72
73enum func_tbl_info {
74	VALID,
75	RX_MODE,
76	MTU,
77	RQ_DEPTH,
78	QUEUE_NUM,
79};
80
81static char *func_table_fields[] = {"valid", "rx_mode", "mtu", "rq_depth", "cfg_q_num"};
82
83static int hinic_dbg_get_func_table(struct hinic_dev *nic_dev, int idx)
84{
85	struct tag_sml_funcfg_tbl *funcfg_table_elem;
86	struct hinic_cmd_lt_rd *read_data;
87	u16 out_size = sizeof(*read_data);
88	int ret = ~0;
89	int err;
90
91	read_data = kzalloc(sizeof(*read_data), GFP_KERNEL);
92	if (!read_data)
93		return ~0;
94
95	read_data->node = TBL_ID_FUNC_CFG_SM_NODE;
96	read_data->inst = TBL_ID_FUNC_CFG_SM_INST;
97	read_data->entry_size = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;
98	read_data->lt_index = HINIC_HWIF_FUNC_IDX(nic_dev->hwdev->hwif);
99	read_data->len = HINIC_FUNCTION_CONFIGURE_TABLE_SIZE;
100
101	err = hinic_port_msg_cmd(nic_dev->hwdev, HINIC_PORT_CMD_RD_LINE_TBL, read_data,
102				 sizeof(*read_data), read_data, &out_size);
103	if (err || out_size != sizeof(*read_data) || read_data->status) {
104		netif_err(nic_dev, drv, nic_dev->netdev,
105			  "Failed to get func table, err: %d, status: 0x%x, out size: 0x%x\n",
106			  err, read_data->status, out_size);
107		kfree(read_data);
108		return ~0;
109	}
110
111	funcfg_table_elem = (struct tag_sml_funcfg_tbl *)read_data->data;
112
113	switch (idx) {
114	case VALID:
115		ret = funcfg_table_elem->dw0.bs.valid;
116		break;
117	case RX_MODE:
118		ret = funcfg_table_elem->dw0.bs.nic_rx_mode;
119		break;
120	case MTU:
121		ret = funcfg_table_elem->dw1.bs.mtu;
122		break;
123	case RQ_DEPTH:
124		ret = funcfg_table_elem->dw13.bs.cfg_rq_depth;
125		break;
126	case QUEUE_NUM:
127		ret = funcfg_table_elem->dw13.bs.cfg_q_num;
128		break;
129	}
130
131	kfree(read_data);
132
133	return ret;
134}
135
136static ssize_t hinic_dbg_cmd_read(struct file *filp, char __user *buffer, size_t count,
137				  loff_t *ppos)
138{
139	struct hinic_debug_priv *dbg;
140	char ret_buf[20];
141	int *desc;
142	u64 out;
143	int ret;
144
145	desc = filp->private_data;
146	dbg = container_of(desc, struct hinic_debug_priv, field_id[*desc]);
147
148	switch (dbg->type) {
149	case HINIC_DBG_SQ_INFO:
150		out = hinic_dbg_get_sq_info(dbg->dev, dbg->object, *desc);
151		break;
152
153	case HINIC_DBG_RQ_INFO:
154		out = hinic_dbg_get_rq_info(dbg->dev, dbg->object, *desc);
155		break;
156
157	case HINIC_DBG_FUNC_TABLE:
158		out = hinic_dbg_get_func_table(dbg->dev, *desc);
159		break;
160
161	default:
162		netif_warn(dbg->dev, drv, dbg->dev->netdev, "Invalid hinic debug cmd: %d\n",
163			   dbg->type);
164		return -EINVAL;
165	}
166
167	ret = snprintf(ret_buf, sizeof(ret_buf), "0x%llx\n", out);
168
169	return simple_read_from_buffer(buffer, count, ppos, ret_buf, ret);
170}
171
172static const struct file_operations hinic_dbg_cmd_fops = {
173	.owner = THIS_MODULE,
174	.open  = simple_open,
175	.read  = hinic_dbg_cmd_read,
176};
177
178static int create_dbg_files(struct hinic_dev *dev, enum hinic_dbg_type type, void *data,
179			    struct dentry *root, struct hinic_debug_priv **dbg, char **field,
180			    int nfile)
181{
182	struct hinic_debug_priv *tmp;
183	int i;
184
185	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
186	if (!tmp)
187		return -ENOMEM;
188
189	tmp->dev = dev;
190	tmp->object = data;
191	tmp->type = type;
192	tmp->root = root;
193
194	for (i = 0; i < nfile; i++) {
195		tmp->field_id[i] = i;
196		debugfs_create_file(field[i], 0400, root, &tmp->field_id[i], &hinic_dbg_cmd_fops);
197	}
198
199	*dbg = tmp;
200
201	return 0;
202}
203
204static void rem_dbg_files(struct hinic_debug_priv *dbg)
205{
206	if (dbg->type != HINIC_DBG_FUNC_TABLE)
207		debugfs_remove_recursive(dbg->root);
208
209	kfree(dbg);
210}
211
212int hinic_sq_debug_add(struct hinic_dev *dev, u16 sq_id)
213{
214	struct hinic_sq *sq;
215	struct dentry *root;
216	char sub_dir[16];
217
218	sq = dev->txqs[sq_id].sq;
219
220	sprintf(sub_dir, "0x%x", sq_id);
221
222	root = debugfs_create_dir(sub_dir, dev->sq_dbgfs);
223
224	return create_dbg_files(dev, HINIC_DBG_SQ_INFO, sq, root, &sq->dbg, sq_fields,
225				ARRAY_SIZE(sq_fields));
226}
227
228void hinic_sq_debug_rem(struct hinic_sq *sq)
229{
230	if (sq->dbg)
231		rem_dbg_files(sq->dbg);
232}
233
234int hinic_rq_debug_add(struct hinic_dev *dev, u16 rq_id)
235{
236	struct hinic_rq *rq;
237	struct dentry *root;
238	char sub_dir[16];
239
240	rq = dev->rxqs[rq_id].rq;
241
242	sprintf(sub_dir, "0x%x", rq_id);
243
244	root = debugfs_create_dir(sub_dir, dev->rq_dbgfs);
245
246	return create_dbg_files(dev, HINIC_DBG_RQ_INFO, rq, root, &rq->dbg, rq_fields,
247				ARRAY_SIZE(rq_fields));
248}
249
250void hinic_rq_debug_rem(struct hinic_rq *rq)
251{
252	if (rq->dbg)
253		rem_dbg_files(rq->dbg);
254}
255
256int hinic_func_table_debug_add(struct hinic_dev *dev)
257{
258	if (HINIC_IS_VF(dev->hwdev->hwif))
259		return 0;
260
261	return create_dbg_files(dev, HINIC_DBG_FUNC_TABLE, dev, dev->func_tbl_dbgfs, &dev->dbg,
262				func_table_fields, ARRAY_SIZE(func_table_fields));
263}
264
265void hinic_func_table_debug_rem(struct hinic_dev *dev)
266{
267	if (!HINIC_IS_VF(dev->hwdev->hwif) && dev->dbg)
268		rem_dbg_files(dev->dbg);
269}
270
271void hinic_sq_dbgfs_init(struct hinic_dev *nic_dev)
272{
273	nic_dev->sq_dbgfs = debugfs_create_dir("SQs", nic_dev->dbgfs_root);
274}
275
276void hinic_sq_dbgfs_uninit(struct hinic_dev *nic_dev)
277{
278	debugfs_remove_recursive(nic_dev->sq_dbgfs);
279}
280
281void hinic_rq_dbgfs_init(struct hinic_dev *nic_dev)
282{
283	nic_dev->rq_dbgfs = debugfs_create_dir("RQs", nic_dev->dbgfs_root);
284}
285
286void hinic_rq_dbgfs_uninit(struct hinic_dev *nic_dev)
287{
288	debugfs_remove_recursive(nic_dev->rq_dbgfs);
289}
290
291void hinic_func_tbl_dbgfs_init(struct hinic_dev *nic_dev)
292{
293	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
294		nic_dev->func_tbl_dbgfs = debugfs_create_dir("func_table", nic_dev->dbgfs_root);
295}
296
297void hinic_func_tbl_dbgfs_uninit(struct hinic_dev *nic_dev)
298{
299	if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
300		debugfs_remove_recursive(nic_dev->func_tbl_dbgfs);
301}
302
303void hinic_dbg_init(struct hinic_dev *nic_dev)
304{
305	nic_dev->dbgfs_root = debugfs_create_dir(pci_name(nic_dev->hwdev->hwif->pdev),
306						 hinic_dbgfs_root);
307}
308
309void hinic_dbg_uninit(struct hinic_dev *nic_dev)
310{
311	debugfs_remove_recursive(nic_dev->dbgfs_root);
312	nic_dev->dbgfs_root = NULL;
313}
314
315void hinic_dbg_register_debugfs(const char *debugfs_dir_name)
316{
317	hinic_dbgfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
318}
319
320void hinic_dbg_unregister_debugfs(void)
321{
322	debugfs_remove_recursive(hinic_dbgfs_root);
323	hinic_dbgfs_root = NULL;
324}
325