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