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