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