xref: /linux/drivers/crypto/hisilicon/debugfs.c (revision 3f4d1482dad9a87c3bf00490fcf339cb5f6d53a8)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 HiSilicon Limited. */
3 #include <linux/hisi_acc_qm.h>
4 #include "qm_common.h"
5 
6 #define QM_DFX_BASE			0x0100000
7 #define QM_DFX_STATE1			0x0104000
8 #define QM_DFX_STATE2			0x01040C8
9 #define QM_DFX_COMMON			0x0000
10 #define QM_DFX_BASE_LEN			0x5A
11 #define QM_DFX_STATE1_LEN		0x2E
12 #define QM_DFX_STATE2_LEN		0x11
13 #define QM_DFX_COMMON_LEN		0xC3
14 #define QM_DFX_REGS_LEN			4UL
15 #define QM_DBG_TMP_BUF_LEN		22
16 #define CURRENT_FUN_MASK		GENMASK(5, 0)
17 #define CURRENT_Q_MASK			GENMASK(31, 16)
18 #define QM_SQE_ADDR_MASK		GENMASK(7, 0)
19 
20 #define QM_DFX_MB_CNT_VF		0x104010
21 #define QM_DFX_DB_CNT_VF		0x104020
22 #define QM_DFX_SQE_CNT_VF_SQN		0x104030
23 #define QM_DFX_CQE_CNT_VF_CQN		0x104040
24 #define QM_DFX_QN_SHIFT			16
25 #define QM_DFX_CNT_CLR_CE		0x100118
26 #define QM_DBG_WRITE_LEN		1024
27 #define QM_IN_IDLE_ST_REG		0x1040e4
28 #define QM_IN_IDLE_STATE		0x1
29 
30 static const char * const qm_debug_file_name[] = {
31 	[CURRENT_QM]   = "current_qm",
32 	[CURRENT_Q]    = "current_q",
33 	[CLEAR_ENABLE] = "clear_enable",
34 };
35 
36 static const char * const qm_s[] = {
37 	"work", "stop",
38 };
39 
40 struct qm_dfx_item {
41 	const char *name;
42 	u32 offset;
43 };
44 
45 struct qm_cmd_dump_item {
46 	const char *cmd;
47 	char *info_name;
48 	int (*dump_fn)(struct hisi_qm *qm, char *cmd, char *info_name);
49 };
50 
51 static struct qm_dfx_item qm_dfx_files[] = {
52 	{"err_irq", offsetof(struct qm_dfx, err_irq_cnt)},
53 	{"aeq_irq", offsetof(struct qm_dfx, aeq_irq_cnt)},
54 	{"abnormal_irq", offsetof(struct qm_dfx, abnormal_irq_cnt)},
55 	{"create_qp_err", offsetof(struct qm_dfx, create_qp_err_cnt)},
56 	{"mb_err", offsetof(struct qm_dfx, mb_err_cnt)},
57 };
58 
59 #define CNT_CYC_REGS_NUM		10
60 static const struct debugfs_reg32 qm_dfx_regs[] = {
61 	/* XXX_CNT are reading clear register */
62 	{"QM_ECC_1BIT_CNT               ",  0x104000},
63 	{"QM_ECC_MBIT_CNT               ",  0x104008},
64 	{"QM_DFX_MB_CNT                 ",  0x104018},
65 	{"QM_DFX_DB_CNT                 ",  0x104028},
66 	{"QM_DFX_SQE_CNT                ",  0x104038},
67 	{"QM_DFX_CQE_CNT                ",  0x104048},
68 	{"QM_DFX_SEND_SQE_TO_ACC_CNT    ",  0x104050},
69 	{"QM_DFX_WB_SQE_FROM_ACC_CNT    ",  0x104058},
70 	{"QM_DFX_ACC_FINISH_CNT         ",  0x104060},
71 	{"QM_DFX_CQE_ERR_CNT            ",  0x1040b4},
72 	{"QM_DFX_FUNS_ACTIVE_ST         ",  0x200},
73 	{"QM_ECC_1BIT_INF               ",  0x104004},
74 	{"QM_ECC_MBIT_INF               ",  0x10400c},
75 	{"QM_DFX_ACC_RDY_VLD0           ",  0x1040a0},
76 	{"QM_DFX_ACC_RDY_VLD1           ",  0x1040a4},
77 	{"QM_DFX_AXI_RDY_VLD            ",  0x1040a8},
78 	{"QM_DFX_FF_ST0                 ",  0x1040c8},
79 	{"QM_DFX_FF_ST1                 ",  0x1040cc},
80 	{"QM_DFX_FF_ST2                 ",  0x1040d0},
81 	{"QM_DFX_FF_ST3                 ",  0x1040d4},
82 	{"QM_DFX_FF_ST4                 ",  0x1040d8},
83 	{"QM_DFX_FF_ST5                 ",  0x1040dc},
84 	{"QM_DFX_FF_ST6                 ",  0x1040e0},
85 	{"QM_IN_IDLE_ST                 ",  0x1040e4},
86 	{"QM_CACHE_CTL                  ",  0x100050},
87 	{"QM_TIMEOUT_CFG                ",  0x100070},
88 	{"QM_DB_TIMEOUT_CFG             ",  0x100074},
89 	{"QM_FLR_PENDING_TIME_CFG       ",  0x100078},
90 	{"QM_ARUSR_MCFG1                ",  0x100088},
91 	{"QM_AWUSR_MCFG1                ",  0x100098},
92 	{"QM_AXI_M_CFG_ENABLE           ",  0x1000B0},
93 	{"QM_RAS_CE_THRESHOLD           ",  0x1000F8},
94 	{"QM_AXI_TIMEOUT_CTRL           ",  0x100120},
95 	{"QM_AXI_TIMEOUT_STATUS         ",  0x100124},
96 	{"QM_CQE_AGGR_TIMEOUT_CTRL      ",  0x100144},
97 	{"ACC_RAS_MSI_INT_SEL           ",  0x1040fc},
98 	{"QM_CQE_OUT                    ",  0x104100},
99 	{"QM_EQE_OUT                    ",  0x104104},
100 	{"QM_AEQE_OUT                   ",  0x104108},
101 	{"QM_DB_INFO0                   ",  0x104180},
102 	{"QM_DB_INFO1                   ",  0x104184},
103 	{"QM_AM_CTRL_GLOBAL             ",  0x300000},
104 	{"QM_AM_CURR_PORT_STS           ",  0x300100},
105 	{"QM_AM_CURR_TRANS_RETURN       ",  0x300150},
106 	{"QM_AM_CURR_RD_MAX_TXID        ",  0x300154},
107 	{"QM_AM_CURR_WR_MAX_TXID        ",  0x300158},
108 	{"QM_AM_ALARM_RRESP             ",  0x300180},
109 	{"QM_AM_ALARM_BRESP             ",  0x300184},
110 };
111 
112 static const struct debugfs_reg32 qm_vf_dfx_regs[] = {
113 	{"QM_DFX_FUNS_ACTIVE_ST         ",  0x200},
114 };
115 
116 /* define the QM's dfx regs region and region length */
117 static struct dfx_diff_registers qm_diff_regs[] = {
118 	{
119 		.reg_offset = QM_DFX_BASE,
120 		.reg_len = QM_DFX_BASE_LEN,
121 	}, {
122 		.reg_offset = QM_DFX_STATE1,
123 		.reg_len = QM_DFX_STATE1_LEN,
124 	}, {
125 		.reg_offset = QM_DFX_STATE2,
126 		.reg_len = QM_DFX_STATE2_LEN,
127 	}, {
128 		.reg_offset = QM_DFX_COMMON,
129 		.reg_len = QM_DFX_COMMON_LEN,
130 	},
131 };
132 
133 static struct hisi_qm *file_to_qm(struct debugfs_file *file)
134 {
135 	struct qm_debug *debug = file->debug;
136 
137 	return container_of(debug, struct hisi_qm, debug);
138 }
139 
140 static ssize_t qm_cmd_read(struct file *filp, char __user *buffer,
141 			   size_t count, loff_t *pos)
142 {
143 	char buf[QM_DBG_READ_LEN];
144 	int len;
145 
146 	len = scnprintf(buf, QM_DBG_READ_LEN, "%s\n",
147 			"Please echo help to cmd to get help information");
148 
149 	return simple_read_from_buffer(buffer, count, pos, buf, len);
150 }
151 
152 static void dump_show(struct hisi_qm *qm, void *info,
153 		     unsigned int info_size, char *info_name)
154 {
155 	struct device *dev = &qm->pdev->dev;
156 	u8 *info_curr = info;
157 	u32 i;
158 #define BYTE_PER_DW	4
159 
160 	dev_info(dev, "%s DUMP\n", info_name);
161 	for (i = 0; i < info_size; i += BYTE_PER_DW, info_curr += BYTE_PER_DW) {
162 		pr_info("DW%u: %02X%02X %02X%02X\n", i / BYTE_PER_DW,
163 			*(info_curr + 3), *(info_curr + 2), *(info_curr + 1), *(info_curr));
164 	}
165 }
166 
167 static int qm_sqc_dump(struct hisi_qm *qm, char *s, char *name)
168 {
169 	struct device *dev = &qm->pdev->dev;
170 	struct qm_sqc *sqc_curr;
171 	struct qm_sqc sqc;
172 	u32 qp_id;
173 	int ret;
174 
175 	if (!s)
176 		return -EINVAL;
177 
178 	ret = kstrtou32(s, 0, &qp_id);
179 	if (ret || qp_id >= qm->qp_num) {
180 		dev_err(dev, "Please input qp num (0-%u)", qm->qp_num - 1);
181 		return -EINVAL;
182 	}
183 
184 	ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp_id, 1);
185 	if (!ret) {
186 		dump_show(qm, &sqc, sizeof(struct qm_sqc), name);
187 
188 		return 0;
189 	}
190 
191 	down_read(&qm->qps_lock);
192 	if (qm->sqc) {
193 		sqc_curr = qm->sqc + qp_id;
194 
195 		dump_show(qm, sqc_curr, sizeof(*sqc_curr), "SOFT SQC");
196 	}
197 	up_read(&qm->qps_lock);
198 
199 	return 0;
200 }
201 
202 static int qm_cqc_dump(struct hisi_qm *qm, char *s, char *name)
203 {
204 	struct device *dev = &qm->pdev->dev;
205 	struct qm_cqc *cqc_curr;
206 	struct qm_cqc cqc;
207 	u32 qp_id;
208 	int ret;
209 
210 	if (!s)
211 		return -EINVAL;
212 
213 	ret = kstrtou32(s, 0, &qp_id);
214 	if (ret || qp_id >= qm->qp_num) {
215 		dev_err(dev, "Please input qp num (0-%u)", qm->qp_num - 1);
216 		return -EINVAL;
217 	}
218 
219 	ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp_id, 1);
220 	if (!ret) {
221 		dump_show(qm, &cqc, sizeof(struct qm_cqc), name);
222 
223 		return 0;
224 	}
225 
226 	down_read(&qm->qps_lock);
227 	if (qm->cqc) {
228 		cqc_curr = qm->cqc + qp_id;
229 
230 		dump_show(qm, cqc_curr, sizeof(*cqc_curr), "SOFT CQC");
231 	}
232 	up_read(&qm->qps_lock);
233 
234 	return 0;
235 }
236 
237 static int qm_eqc_aeqc_dump(struct hisi_qm *qm, char *s, char *name)
238 {
239 	struct device *dev = &qm->pdev->dev;
240 	struct qm_aeqc aeqc;
241 	struct qm_eqc eqc;
242 	size_t size;
243 	void *xeqc;
244 	int ret;
245 	u8 cmd;
246 
247 	if (strsep(&s, " ")) {
248 		dev_err(dev, "Please do not input extra characters!\n");
249 		return -EINVAL;
250 	}
251 
252 	if (!strcmp(name, "EQC")) {
253 		cmd = QM_MB_CMD_EQC;
254 		size = sizeof(struct qm_eqc);
255 		xeqc = &eqc;
256 	} else {
257 		cmd = QM_MB_CMD_AEQC;
258 		size = sizeof(struct qm_aeqc);
259 		xeqc = &aeqc;
260 	}
261 
262 	ret = qm_set_and_get_xqc(qm, cmd, xeqc, 0, 1);
263 	if (ret)
264 		return ret;
265 
266 	dump_show(qm, xeqc, size, name);
267 
268 	return ret;
269 }
270 
271 static int q_dump_param_parse(struct hisi_qm *qm, char *s,
272 			      u32 *e_id, u32 *q_id, u16 q_depth)
273 {
274 	struct device *dev = &qm->pdev->dev;
275 	unsigned int qp_num = qm->qp_num;
276 	char *presult;
277 	int ret;
278 
279 	presult = strsep(&s, " ");
280 	if (!presult) {
281 		dev_err(dev, "Please input qp number!\n");
282 		return -EINVAL;
283 	}
284 
285 	ret = kstrtou32(presult, 0, q_id);
286 	if (ret || *q_id >= qp_num) {
287 		dev_err(dev, "Please input qp num (0-%u)", qp_num - 1);
288 		return -EINVAL;
289 	}
290 
291 	presult = strsep(&s, " ");
292 	if (!presult) {
293 		dev_err(dev, "Please input sqe number!\n");
294 		return -EINVAL;
295 	}
296 
297 	ret = kstrtou32(presult, 0, e_id);
298 	if (ret || *e_id >= q_depth) {
299 		dev_err(dev, "Please input sqe num (0-%u)", q_depth - 1);
300 		return -EINVAL;
301 	}
302 
303 	if (strsep(&s, " ")) {
304 		dev_err(dev, "Please do not input extra characters!\n");
305 		return -EINVAL;
306 	}
307 
308 	return 0;
309 }
310 
311 static int qm_sq_dump(struct hisi_qm *qm, char *s, char *name)
312 {
313 	u16 sq_depth = qm->qp_array->cq_depth;
314 	void *sqe;
315 	struct hisi_qp *qp;
316 	u32 qp_id, sqe_id;
317 	int ret;
318 
319 	ret = q_dump_param_parse(qm, s, &sqe_id, &qp_id, sq_depth);
320 	if (ret)
321 		return ret;
322 
323 	sqe = kzalloc(qm->sqe_size, GFP_KERNEL);
324 	if (!sqe)
325 		return -ENOMEM;
326 
327 	qp = &qm->qp_array[qp_id];
328 	memcpy(sqe, qp->sqe + sqe_id * qm->sqe_size, qm->sqe_size);
329 	memset(sqe + qm->debug.sqe_mask_offset, QM_SQE_ADDR_MASK,
330 	       qm->debug.sqe_mask_len);
331 
332 	dump_show(qm, sqe, qm->sqe_size, name);
333 
334 	kfree(sqe);
335 
336 	return 0;
337 }
338 
339 static int qm_cq_dump(struct hisi_qm *qm, char *s, char *name)
340 {
341 	struct qm_cqe *cqe_curr;
342 	struct hisi_qp *qp;
343 	u32 qp_id, cqe_id;
344 	int ret;
345 
346 	ret = q_dump_param_parse(qm, s, &cqe_id, &qp_id, qm->qp_array->cq_depth);
347 	if (ret)
348 		return ret;
349 
350 	qp = &qm->qp_array[qp_id];
351 	cqe_curr = qp->cqe + cqe_id;
352 	dump_show(qm, cqe_curr, sizeof(struct qm_cqe), name);
353 
354 	return 0;
355 }
356 
357 static int qm_eq_aeq_dump(struct hisi_qm *qm, char *s, char *name)
358 {
359 	struct device *dev = &qm->pdev->dev;
360 	u16 xeq_depth;
361 	size_t size;
362 	void *xeqe;
363 	u32 xeqe_id;
364 	int ret;
365 
366 	if (!s)
367 		return -EINVAL;
368 
369 	ret = kstrtou32(s, 0, &xeqe_id);
370 	if (ret)
371 		return -EINVAL;
372 
373 	if (!strcmp(name, "EQE")) {
374 		xeq_depth = qm->eq_depth;
375 		size = sizeof(struct qm_eqe);
376 	} else {
377 		xeq_depth = qm->aeq_depth;
378 		size = sizeof(struct qm_aeqe);
379 	}
380 
381 	if (xeqe_id >= xeq_depth) {
382 		dev_err(dev, "Please input eqe or aeqe num (0-%u)", xeq_depth - 1);
383 		return -EINVAL;
384 	}
385 
386 	down_read(&qm->qps_lock);
387 
388 	if (qm->eqe && !strcmp(name, "EQE")) {
389 		xeqe = qm->eqe + xeqe_id;
390 	} else if (qm->aeqe && !strcmp(name, "AEQE")) {
391 		xeqe = qm->aeqe + xeqe_id;
392 	} else {
393 		ret = -EINVAL;
394 		goto err_unlock;
395 	}
396 
397 	dump_show(qm, xeqe, size, name);
398 
399 err_unlock:
400 	up_read(&qm->qps_lock);
401 	return ret;
402 }
403 
404 static int qm_dbg_help(struct hisi_qm *qm, char *s)
405 {
406 	struct device *dev = &qm->pdev->dev;
407 
408 	if (strsep(&s, " ")) {
409 		dev_err(dev, "Please do not input extra characters!\n");
410 		return -EINVAL;
411 	}
412 
413 	dev_info(dev, "available commands:\n");
414 	dev_info(dev, "sqc <num>\n");
415 	dev_info(dev, "cqc <num>\n");
416 	dev_info(dev, "eqc\n");
417 	dev_info(dev, "aeqc\n");
418 	dev_info(dev, "sq <num> <e>\n");
419 	dev_info(dev, "cq <num> <e>\n");
420 	dev_info(dev, "eq <e>\n");
421 	dev_info(dev, "aeq <e>\n");
422 
423 	return 0;
424 }
425 
426 static const struct qm_cmd_dump_item qm_cmd_dump_table[] = {
427 	{
428 		.cmd = "sqc",
429 		.info_name = "SQC",
430 		.dump_fn = qm_sqc_dump,
431 	}, {
432 		.cmd = "cqc",
433 		.info_name = "CQC",
434 		.dump_fn = qm_cqc_dump,
435 	}, {
436 		.cmd = "eqc",
437 		.info_name = "EQC",
438 		.dump_fn = qm_eqc_aeqc_dump,
439 	}, {
440 		.cmd = "aeqc",
441 		.info_name = "AEQC",
442 		.dump_fn = qm_eqc_aeqc_dump,
443 	}, {
444 		.cmd = "sq",
445 		.info_name = "SQE",
446 		.dump_fn = qm_sq_dump,
447 	}, {
448 		.cmd = "cq",
449 		.info_name = "CQE",
450 		.dump_fn = qm_cq_dump,
451 	}, {
452 		.cmd = "eq",
453 		.info_name = "EQE",
454 		.dump_fn = qm_eq_aeq_dump,
455 	}, {
456 		.cmd = "aeq",
457 		.info_name = "AEQE",
458 		.dump_fn = qm_eq_aeq_dump,
459 	},
460 };
461 
462 static int qm_cmd_write_dump(struct hisi_qm *qm, const char *cmd_buf)
463 {
464 	struct device *dev = &qm->pdev->dev;
465 	char *presult, *s, *s_tmp;
466 	int table_size, i, ret;
467 
468 	s = kstrdup(cmd_buf, GFP_KERNEL);
469 	if (!s)
470 		return -ENOMEM;
471 
472 	s_tmp = s;
473 	presult = strsep(&s, " ");
474 	if (!presult) {
475 		ret = -EINVAL;
476 		goto err_buffer_free;
477 	}
478 
479 	if (!strcmp(presult, "help")) {
480 		ret = qm_dbg_help(qm, s);
481 		goto err_buffer_free;
482 	}
483 
484 	table_size = ARRAY_SIZE(qm_cmd_dump_table);
485 	for (i = 0; i < table_size; i++) {
486 		if (!strcmp(presult, qm_cmd_dump_table[i].cmd)) {
487 			ret = qm_cmd_dump_table[i].dump_fn(qm, s,
488 				qm_cmd_dump_table[i].info_name);
489 			break;
490 		}
491 	}
492 
493 	if (i == table_size) {
494 		dev_info(dev, "Please echo help\n");
495 		ret = -EINVAL;
496 	}
497 
498 err_buffer_free:
499 	kfree(s_tmp);
500 
501 	return ret;
502 }
503 
504 static ssize_t qm_cmd_write(struct file *filp, const char __user *buffer,
505 			    size_t count, loff_t *pos)
506 {
507 	struct hisi_qm *qm = filp->private_data;
508 	char *cmd_buf, *cmd_buf_tmp;
509 	int ret;
510 
511 	if (*pos)
512 		return 0;
513 
514 	ret = hisi_qm_get_dfx_access(qm);
515 	if (ret)
516 		return ret;
517 
518 	/* Judge if the instance is being reset. */
519 	if (unlikely(atomic_read(&qm->status.flags) == QM_STOP)) {
520 		ret = 0;
521 		goto put_dfx_access;
522 	}
523 
524 	if (count > QM_DBG_WRITE_LEN) {
525 		ret = -ENOSPC;
526 		goto put_dfx_access;
527 	}
528 
529 	cmd_buf = memdup_user_nul(buffer, count);
530 	if (IS_ERR(cmd_buf)) {
531 		ret = PTR_ERR(cmd_buf);
532 		goto put_dfx_access;
533 	}
534 
535 	cmd_buf_tmp = strchr(cmd_buf, '\n');
536 	if (cmd_buf_tmp) {
537 		*cmd_buf_tmp = '\0';
538 		count = cmd_buf_tmp - cmd_buf + 1;
539 	}
540 
541 	ret = qm_cmd_write_dump(qm, cmd_buf);
542 	if (ret) {
543 		kfree(cmd_buf);
544 		goto put_dfx_access;
545 	}
546 
547 	kfree(cmd_buf);
548 
549 	ret = count;
550 
551 put_dfx_access:
552 	hisi_qm_put_dfx_access(qm);
553 	return ret;
554 }
555 
556 static const struct file_operations qm_cmd_fops = {
557 	.owner = THIS_MODULE,
558 	.open = simple_open,
559 	.read = qm_cmd_read,
560 	.write = qm_cmd_write,
561 };
562 
563 /**
564  * hisi_qm_regs_dump() - Dump registers's value.
565  * @s: debugfs file handle.
566  * @regset: accelerator registers information.
567  *
568  * Dump accelerator registers.
569  */
570 void hisi_qm_regs_dump(struct seq_file *s, struct debugfs_regset32 *regset)
571 {
572 	struct pci_dev *pdev = to_pci_dev(regset->dev);
573 	struct hisi_qm *qm = pci_get_drvdata(pdev);
574 	const struct debugfs_reg32 *regs = regset->regs;
575 	int regs_len = regset->nregs;
576 	int i, ret;
577 	u32 val;
578 
579 	ret = hisi_qm_get_dfx_access(qm);
580 	if (ret)
581 		return;
582 
583 	for (i = 0; i < regs_len; i++) {
584 		val = readl(regset->base + regs[i].offset);
585 		seq_printf(s, "%s= 0x%08x\n", regs[i].name, val);
586 	}
587 
588 	hisi_qm_put_dfx_access(qm);
589 }
590 EXPORT_SYMBOL_GPL(hisi_qm_regs_dump);
591 
592 static int qm_regs_show(struct seq_file *s, void *unused)
593 {
594 	struct hisi_qm *qm = s->private;
595 	struct debugfs_regset32 regset;
596 
597 	if (qm->fun_type == QM_HW_PF) {
598 		regset.regs = qm_dfx_regs;
599 		regset.nregs = ARRAY_SIZE(qm_dfx_regs);
600 	} else {
601 		regset.regs = qm_vf_dfx_regs;
602 		regset.nregs = ARRAY_SIZE(qm_vf_dfx_regs);
603 	}
604 
605 	regset.base = qm->io_base;
606 	regset.dev = &qm->pdev->dev;
607 
608 	hisi_qm_regs_dump(s, &regset);
609 
610 	return 0;
611 }
612 
613 DEFINE_SHOW_ATTRIBUTE(qm_regs);
614 
615 static u32 current_q_read(struct hisi_qm *qm)
616 {
617 	return readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) >> QM_DFX_QN_SHIFT;
618 }
619 
620 static int current_q_write(struct hisi_qm *qm, u32 val)
621 {
622 	u32 tmp;
623 
624 	if (val >= qm->debug.curr_qm_qp_num)
625 		return -EINVAL;
626 
627 	tmp = val << QM_DFX_QN_SHIFT |
628 	      (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_FUN_MASK);
629 	writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
630 
631 	tmp = val << QM_DFX_QN_SHIFT |
632 	      (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_FUN_MASK);
633 	writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
634 
635 	return 0;
636 }
637 
638 static u32 clear_enable_read(struct hisi_qm *qm)
639 {
640 	return readl(qm->io_base + QM_DFX_CNT_CLR_CE);
641 }
642 
643 /* rd_clr_ctrl 1 enable read clear, otherwise 0 disable it */
644 static int clear_enable_write(struct hisi_qm *qm, u32 rd_clr_ctrl)
645 {
646 	if (rd_clr_ctrl > 1)
647 		return -EINVAL;
648 
649 	writel(rd_clr_ctrl, qm->io_base + QM_DFX_CNT_CLR_CE);
650 
651 	return 0;
652 }
653 
654 static u32 current_qm_read(struct hisi_qm *qm)
655 {
656 	return readl(qm->io_base + QM_DFX_MB_CNT_VF);
657 }
658 
659 static int qm_get_vf_qp_num(struct hisi_qm *qm, u32 fun_num)
660 {
661 	u32 remain_q_num, vfq_num;
662 	u32 num_vfs = qm->vfs_num;
663 
664 	vfq_num = (qm->ctrl_qp_num - qm->qp_num) / num_vfs;
665 	if (vfq_num >= qm->max_qp_num)
666 		return qm->max_qp_num;
667 
668 	remain_q_num = (qm->ctrl_qp_num - qm->qp_num) % num_vfs;
669 	if (vfq_num + remain_q_num <= qm->max_qp_num)
670 		return fun_num == num_vfs ? vfq_num + remain_q_num : vfq_num;
671 
672 	/*
673 	 * if vfq_num + remain_q_num > max_qp_num, the last VFs,
674 	 * each with one more queue.
675 	 */
676 	return fun_num + remain_q_num > num_vfs ? vfq_num + 1 : vfq_num;
677 }
678 
679 static int current_qm_write(struct hisi_qm *qm, u32 val)
680 {
681 	u32 tmp;
682 
683 	if (val > qm->vfs_num)
684 		return -EINVAL;
685 
686 	/* According PF or VF Dev ID to calculation curr_qm_qp_num and store */
687 	if (!val)
688 		qm->debug.curr_qm_qp_num = qm->qp_num;
689 	else
690 		qm->debug.curr_qm_qp_num = qm_get_vf_qp_num(qm, val);
691 
692 	writel(val, qm->io_base + QM_DFX_MB_CNT_VF);
693 	writel(val, qm->io_base + QM_DFX_DB_CNT_VF);
694 
695 	tmp = val |
696 	      (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK);
697 	writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
698 
699 	tmp = val |
700 	      (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK);
701 	writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
702 
703 	return 0;
704 }
705 
706 static ssize_t qm_debug_read(struct file *filp, char __user *buf,
707 			     size_t count, loff_t *pos)
708 {
709 	struct debugfs_file *file = filp->private_data;
710 	enum qm_debug_file index = file->index;
711 	struct hisi_qm *qm = file_to_qm(file);
712 	char tbuf[QM_DBG_TMP_BUF_LEN];
713 	u32 val;
714 	int ret;
715 
716 	ret = hisi_qm_get_dfx_access(qm);
717 	if (ret)
718 		return ret;
719 
720 	mutex_lock(&file->lock);
721 	switch (index) {
722 	case CURRENT_QM:
723 		val = current_qm_read(qm);
724 		break;
725 	case CURRENT_Q:
726 		val = current_q_read(qm);
727 		break;
728 	case CLEAR_ENABLE:
729 		val = clear_enable_read(qm);
730 		break;
731 	default:
732 		goto err_input;
733 	}
734 	mutex_unlock(&file->lock);
735 
736 	hisi_qm_put_dfx_access(qm);
737 	ret = scnprintf(tbuf, QM_DBG_TMP_BUF_LEN, "%u\n", val);
738 	return simple_read_from_buffer(buf, count, pos, tbuf, ret);
739 
740 err_input:
741 	mutex_unlock(&file->lock);
742 	hisi_qm_put_dfx_access(qm);
743 	return -EINVAL;
744 }
745 
746 static ssize_t qm_debug_write(struct file *filp, const char __user *buf,
747 			      size_t count, loff_t *pos)
748 {
749 	struct debugfs_file *file = filp->private_data;
750 	enum qm_debug_file index = file->index;
751 	struct hisi_qm *qm = file_to_qm(file);
752 	unsigned long val;
753 	char tbuf[QM_DBG_TMP_BUF_LEN];
754 	int len, ret;
755 
756 	if (*pos != 0)
757 		return 0;
758 
759 	if (count >= QM_DBG_TMP_BUF_LEN)
760 		return -ENOSPC;
761 
762 	len = simple_write_to_buffer(tbuf, QM_DBG_TMP_BUF_LEN - 1, pos, buf,
763 				     count);
764 	if (len < 0)
765 		return len;
766 
767 	tbuf[len] = '\0';
768 	if (kstrtoul(tbuf, 0, &val))
769 		return -EFAULT;
770 
771 	ret = hisi_qm_get_dfx_access(qm);
772 	if (ret)
773 		return ret;
774 
775 	mutex_lock(&file->lock);
776 	switch (index) {
777 	case CURRENT_QM:
778 		ret = current_qm_write(qm, val);
779 		break;
780 	case CURRENT_Q:
781 		ret = current_q_write(qm, val);
782 		break;
783 	case CLEAR_ENABLE:
784 		ret = clear_enable_write(qm, val);
785 		break;
786 	default:
787 		ret = -EINVAL;
788 	}
789 	mutex_unlock(&file->lock);
790 
791 	hisi_qm_put_dfx_access(qm);
792 
793 	if (ret)
794 		return ret;
795 
796 	return count;
797 }
798 
799 static const struct file_operations qm_debug_fops = {
800 	.owner = THIS_MODULE,
801 	.open = simple_open,
802 	.read = qm_debug_read,
803 	.write = qm_debug_write,
804 };
805 
806 static void dfx_regs_uninit(struct hisi_qm *qm,
807 		struct dfx_diff_registers *dregs, int reg_len)
808 {
809 	int i;
810 
811 	if (!dregs)
812 		return;
813 
814 	/* Setting the pointer is NULL to prevent double free */
815 	for (i = 0; i < reg_len; i++) {
816 		if (!dregs[i].regs)
817 			continue;
818 
819 		kfree(dregs[i].regs);
820 		dregs[i].regs = NULL;
821 	}
822 	kfree(dregs);
823 }
824 
825 static struct dfx_diff_registers *dfx_regs_init(struct hisi_qm *qm,
826 	const struct dfx_diff_registers *cregs, u32 reg_len)
827 {
828 	struct dfx_diff_registers *diff_regs;
829 	u32 j, base_offset;
830 	int i;
831 
832 	diff_regs = kcalloc(reg_len, sizeof(*diff_regs), GFP_KERNEL);
833 	if (!diff_regs)
834 		return ERR_PTR(-ENOMEM);
835 
836 	for (i = 0; i < reg_len; i++) {
837 		if (!cregs[i].reg_len)
838 			continue;
839 
840 		diff_regs[i].reg_offset = cregs[i].reg_offset;
841 		diff_regs[i].reg_len = cregs[i].reg_len;
842 		diff_regs[i].regs = kcalloc(QM_DFX_REGS_LEN, cregs[i].reg_len,
843 					 GFP_KERNEL);
844 		if (!diff_regs[i].regs)
845 			goto alloc_error;
846 
847 		for (j = 0; j < diff_regs[i].reg_len; j++) {
848 			base_offset = diff_regs[i].reg_offset +
849 					j * QM_DFX_REGS_LEN;
850 			diff_regs[i].regs[j] = readl(qm->io_base + base_offset);
851 		}
852 	}
853 
854 	return diff_regs;
855 
856 alloc_error:
857 	while (i > 0) {
858 		i--;
859 		kfree(diff_regs[i].regs);
860 	}
861 	kfree(diff_regs);
862 	return ERR_PTR(-ENOMEM);
863 }
864 
865 static int qm_diff_regs_init(struct hisi_qm *qm,
866 		struct dfx_diff_registers *dregs, u32 reg_len)
867 {
868 	int ret;
869 
870 	qm->debug.qm_diff_regs = dfx_regs_init(qm, qm_diff_regs, ARRAY_SIZE(qm_diff_regs));
871 	if (IS_ERR(qm->debug.qm_diff_regs)) {
872 		ret = PTR_ERR(qm->debug.qm_diff_regs);
873 		qm->debug.qm_diff_regs = NULL;
874 		return ret;
875 	}
876 
877 	qm->debug.acc_diff_regs = dfx_regs_init(qm, dregs, reg_len);
878 	if (IS_ERR(qm->debug.acc_diff_regs)) {
879 		dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs));
880 		ret = PTR_ERR(qm->debug.acc_diff_regs);
881 		qm->debug.acc_diff_regs = NULL;
882 		return ret;
883 	}
884 
885 	return 0;
886 }
887 
888 static void qm_last_regs_uninit(struct hisi_qm *qm)
889 {
890 	struct qm_debug *debug = &qm->debug;
891 
892 	if (qm->fun_type == QM_HW_VF || !debug->qm_last_words)
893 		return;
894 
895 	kfree(debug->qm_last_words);
896 	debug->qm_last_words = NULL;
897 }
898 
899 static int qm_last_regs_init(struct hisi_qm *qm)
900 {
901 	int dfx_regs_num = ARRAY_SIZE(qm_dfx_regs);
902 	struct qm_debug *debug = &qm->debug;
903 	int i;
904 
905 	if (qm->fun_type == QM_HW_VF)
906 		return 0;
907 
908 	debug->qm_last_words = kcalloc(dfx_regs_num, sizeof(unsigned int), GFP_KERNEL);
909 	if (!debug->qm_last_words)
910 		return -ENOMEM;
911 
912 	for (i = 0; i < dfx_regs_num; i++) {
913 		debug->qm_last_words[i] = readl_relaxed(qm->io_base +
914 			qm_dfx_regs[i].offset);
915 	}
916 
917 	return 0;
918 }
919 
920 static void qm_diff_regs_uninit(struct hisi_qm *qm, u32 reg_len)
921 {
922 	dfx_regs_uninit(qm, qm->debug.acc_diff_regs, reg_len);
923 	qm->debug.acc_diff_regs = NULL;
924 	dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs));
925 	qm->debug.qm_diff_regs = NULL;
926 }
927 
928 /**
929  * hisi_qm_regs_debugfs_init() - Allocate memory for registers.
930  * @qm: device qm handle.
931  * @dregs: diff registers handle.
932  * @reg_len: diff registers region length.
933  */
934 int hisi_qm_regs_debugfs_init(struct hisi_qm *qm,
935 		struct dfx_diff_registers *dregs, u32 reg_len)
936 {
937 	int ret;
938 
939 	if (!qm || !dregs)
940 		return -EINVAL;
941 
942 	if (qm->fun_type != QM_HW_PF)
943 		return 0;
944 
945 	ret = qm_last_regs_init(qm);
946 	if (ret) {
947 		dev_info(&qm->pdev->dev, "failed to init qm words memory!\n");
948 		return ret;
949 	}
950 
951 	ret = qm_diff_regs_init(qm, dregs, reg_len);
952 	if (ret) {
953 		qm_last_regs_uninit(qm);
954 		return ret;
955 	}
956 
957 	return 0;
958 }
959 EXPORT_SYMBOL_GPL(hisi_qm_regs_debugfs_init);
960 
961 /**
962  * hisi_qm_regs_debugfs_uninit() - Free memory for registers.
963  * @qm: device qm handle.
964  * @reg_len: diff registers region length.
965  */
966 void hisi_qm_regs_debugfs_uninit(struct hisi_qm *qm, u32 reg_len)
967 {
968 	if (!qm || qm->fun_type != QM_HW_PF)
969 		return;
970 
971 	qm_diff_regs_uninit(qm, reg_len);
972 	qm_last_regs_uninit(qm);
973 }
974 EXPORT_SYMBOL_GPL(hisi_qm_regs_debugfs_uninit);
975 
976 /**
977  * hisi_qm_acc_diff_regs_dump() - Dump registers's value.
978  * @qm: device qm handle.
979  * @s: Debugfs file handle.
980  * @dregs: diff registers handle.
981  * @regs_len: diff registers region length.
982  */
983 void hisi_qm_acc_diff_regs_dump(struct hisi_qm *qm, struct seq_file *s,
984 	struct dfx_diff_registers *dregs, u32 regs_len)
985 {
986 	u32 j, val, base_offset;
987 	int i, ret;
988 
989 	if (!qm || !s || !dregs)
990 		return;
991 
992 	ret = hisi_qm_get_dfx_access(qm);
993 	if (ret)
994 		return;
995 
996 	down_read(&qm->qps_lock);
997 	for (i = 0; i < regs_len; i++) {
998 		if (!dregs[i].reg_len)
999 			continue;
1000 
1001 		for (j = 0; j < dregs[i].reg_len; j++) {
1002 			base_offset = dregs[i].reg_offset + j * QM_DFX_REGS_LEN;
1003 			val = readl(qm->io_base + base_offset);
1004 			if (val != dregs[i].regs[j])
1005 				seq_printf(s, "0x%08x = 0x%08x ---> 0x%08x\n",
1006 					   base_offset, dregs[i].regs[j], val);
1007 		}
1008 	}
1009 	up_read(&qm->qps_lock);
1010 
1011 	hisi_qm_put_dfx_access(qm);
1012 }
1013 EXPORT_SYMBOL_GPL(hisi_qm_acc_diff_regs_dump);
1014 
1015 void hisi_qm_show_last_dfx_regs(struct hisi_qm *qm)
1016 {
1017 	struct qm_debug *debug = &qm->debug;
1018 	struct pci_dev *pdev = qm->pdev;
1019 	u32 val;
1020 	int i;
1021 
1022 	if (qm->fun_type == QM_HW_VF || !debug->qm_last_words)
1023 		return;
1024 
1025 	for (i = 0; i < ARRAY_SIZE(qm_dfx_regs); i++) {
1026 		val = readl_relaxed(qm->io_base + qm_dfx_regs[i].offset);
1027 		if (debug->qm_last_words[i] != val)
1028 			pci_info(pdev, "%s \t= 0x%08x => 0x%08x\n",
1029 			qm_dfx_regs[i].name, debug->qm_last_words[i], val);
1030 	}
1031 }
1032 
1033 static int qm_diff_regs_show(struct seq_file *s, void *unused)
1034 {
1035 	struct hisi_qm *qm = s->private;
1036 
1037 	hisi_qm_acc_diff_regs_dump(qm, s, qm->debug.qm_diff_regs,
1038 					ARRAY_SIZE(qm_diff_regs));
1039 
1040 	return 0;
1041 }
1042 DEFINE_SHOW_ATTRIBUTE(qm_diff_regs);
1043 
1044 static int qm_state_show(struct seq_file *s, void *unused)
1045 {
1046 	struct hisi_qm *qm = s->private;
1047 	u32 val;
1048 	int ret;
1049 
1050 	/* If device is in suspended, directly return the idle state. */
1051 	ret = hisi_qm_get_dfx_access(qm);
1052 	if (!ret) {
1053 		val = readl(qm->io_base + QM_IN_IDLE_ST_REG);
1054 		hisi_qm_put_dfx_access(qm);
1055 	} else if (ret == -EAGAIN) {
1056 		val = QM_IN_IDLE_STATE;
1057 	} else {
1058 		return ret;
1059 	}
1060 
1061 	seq_printf(s, "%u\n", val);
1062 
1063 	return 0;
1064 }
1065 
1066 DEFINE_SHOW_ATTRIBUTE(qm_state);
1067 
1068 static ssize_t qm_status_read(struct file *filp, char __user *buffer,
1069 			      size_t count, loff_t *pos)
1070 {
1071 	struct hisi_qm *qm = filp->private_data;
1072 	char buf[QM_DBG_READ_LEN];
1073 	int val, len;
1074 
1075 	val = atomic_read(&qm->status.flags);
1076 	len = scnprintf(buf, QM_DBG_READ_LEN, "%s\n", qm_s[val]);
1077 
1078 	return simple_read_from_buffer(buffer, count, pos, buf, len);
1079 }
1080 
1081 static const struct file_operations qm_status_fops = {
1082 	.owner = THIS_MODULE,
1083 	.open = simple_open,
1084 	.read = qm_status_read,
1085 };
1086 
1087 static void qm_create_debugfs_file(struct hisi_qm *qm, struct dentry *dir,
1088 				   enum qm_debug_file index)
1089 {
1090 	struct debugfs_file *file = qm->debug.files + index;
1091 
1092 	file->index = index;
1093 	mutex_init(&file->lock);
1094 	file->debug = &qm->debug;
1095 
1096 	debugfs_create_file(qm_debug_file_name[index], 0600, dir, file,
1097 			    &qm_debug_fops);
1098 }
1099 
1100 static int qm_debugfs_atomic64_set(void *data, u64 val)
1101 {
1102 	if (val)
1103 		return -EINVAL;
1104 
1105 	atomic64_set((atomic64_t *)data, 0);
1106 
1107 	return 0;
1108 }
1109 
1110 static int qm_debugfs_atomic64_get(void *data, u64 *val)
1111 {
1112 	*val = atomic64_read((atomic64_t *)data);
1113 
1114 	return 0;
1115 }
1116 
1117 DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get,
1118 			 qm_debugfs_atomic64_set, "%llu\n");
1119 
1120 /**
1121  * hisi_qm_debug_init() - Initialize qm related debugfs files.
1122  * @qm: The qm for which we want to add debugfs files.
1123  *
1124  * Create qm related debugfs files.
1125  */
1126 void hisi_qm_debug_init(struct hisi_qm *qm)
1127 {
1128 	struct dfx_diff_registers *qm_regs = qm->debug.qm_diff_regs;
1129 	struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx;
1130 	struct qm_dfx *dfx = &qm->debug.dfx;
1131 	struct dentry *qm_d;
1132 	void *data;
1133 	int i;
1134 
1135 	qm_d = debugfs_create_dir("qm", qm->debug.debug_root);
1136 	qm->debug.qm_d = qm_d;
1137 
1138 	/* only show this in PF */
1139 	if (qm->fun_type == QM_HW_PF) {
1140 		debugfs_create_file("qm_state", 0444, qm->debug.qm_d,
1141 					qm, &qm_state_fops);
1142 
1143 		qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM);
1144 		for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++)
1145 			qm_create_debugfs_file(qm, qm->debug.qm_d, i);
1146 	}
1147 
1148 	if (qm_regs)
1149 		debugfs_create_file("diff_regs", 0444, qm->debug.qm_d,
1150 					qm, &qm_diff_regs_fops);
1151 
1152 	debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
1153 
1154 	debugfs_create_file("cmd", 0600, qm->debug.qm_d, qm, &qm_cmd_fops);
1155 
1156 	debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
1157 			&qm_status_fops);
1158 
1159 	debugfs_create_u32("dev_state", 0444, qm->debug.qm_d, &dev_dfx->dev_state);
1160 	debugfs_create_u32("dev_timeout", 0644, qm->debug.qm_d, &dev_dfx->dev_timeout);
1161 
1162 	for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
1163 		data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
1164 		debugfs_create_file(qm_dfx_files[i].name,
1165 			0644,
1166 			qm_d,
1167 			data,
1168 			&qm_atomic64_ops);
1169 	}
1170 
1171 	if (test_bit(QM_SUPPORT_FUNC_QOS, &qm->caps))
1172 		hisi_qm_set_algqos_init(qm);
1173 }
1174 EXPORT_SYMBOL_GPL(hisi_qm_debug_init);
1175 
1176 /**
1177  * hisi_qm_debug_regs_clear() - clear qm debug related registers.
1178  * @qm: The qm for which we want to clear its debug registers.
1179  */
1180 void hisi_qm_debug_regs_clear(struct hisi_qm *qm)
1181 {
1182 	const struct debugfs_reg32 *regs;
1183 	int i;
1184 
1185 	/* clear current_qm */
1186 	writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
1187 	writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
1188 
1189 	/* clear current_q */
1190 	writel(0x0, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
1191 	writel(0x0, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
1192 
1193 	/*
1194 	 * these registers are reading and clearing, so clear them after
1195 	 * reading them.
1196 	 */
1197 	writel(0x1, qm->io_base + QM_DFX_CNT_CLR_CE);
1198 
1199 	regs = qm_dfx_regs;
1200 	for (i = 0; i < CNT_CYC_REGS_NUM; i++) {
1201 		readl(qm->io_base + regs->offset);
1202 		regs++;
1203 	}
1204 
1205 	/* clear clear_enable */
1206 	writel(0x0, qm->io_base + QM_DFX_CNT_CLR_CE);
1207 }
1208 EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
1209