xref: /linux/drivers/crypto/hisilicon/debugfs.c (revision e6a901a00822659181c93c86d8bbc2a17779fddc)
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, *sqe_curr;
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 * sq_depth, GFP_KERNEL);
324 	if (!sqe)
325 		return -ENOMEM;
326 
327 	qp = &qm->qp_array[qp_id];
328 	memcpy(sqe, qp->sqe, qm->sqe_size * sq_depth);
329 	sqe_curr = sqe + (u32)(sqe_id * qm->sqe_size);
330 	memset(sqe_curr + qm->debug.sqe_mask_offset, QM_SQE_ADDR_MASK,
331 	       qm->debug.sqe_mask_len);
332 
333 	dump_show(qm, sqe_curr, qm->sqe_size, name);
334 
335 	kfree(sqe);
336 
337 	return 0;
338 }
339 
340 static int qm_cq_dump(struct hisi_qm *qm, char *s, char *name)
341 {
342 	struct qm_cqe *cqe_curr;
343 	struct hisi_qp *qp;
344 	u32 qp_id, cqe_id;
345 	int ret;
346 
347 	ret = q_dump_param_parse(qm, s, &cqe_id, &qp_id, qm->qp_array->cq_depth);
348 	if (ret)
349 		return ret;
350 
351 	qp = &qm->qp_array[qp_id];
352 	cqe_curr = qp->cqe + cqe_id;
353 	dump_show(qm, cqe_curr, sizeof(struct qm_cqe), name);
354 
355 	return 0;
356 }
357 
358 static int qm_eq_aeq_dump(struct hisi_qm *qm, char *s, char *name)
359 {
360 	struct device *dev = &qm->pdev->dev;
361 	u16 xeq_depth;
362 	size_t size;
363 	void *xeqe;
364 	u32 xeqe_id;
365 	int ret;
366 
367 	if (!s)
368 		return -EINVAL;
369 
370 	ret = kstrtou32(s, 0, &xeqe_id);
371 	if (ret)
372 		return -EINVAL;
373 
374 	if (!strcmp(name, "EQE")) {
375 		xeq_depth = qm->eq_depth;
376 		size = sizeof(struct qm_eqe);
377 	} else {
378 		xeq_depth = qm->aeq_depth;
379 		size = sizeof(struct qm_aeqe);
380 	}
381 
382 	if (xeqe_id >= xeq_depth) {
383 		dev_err(dev, "Please input eqe or aeqe num (0-%u)", xeq_depth - 1);
384 		return -EINVAL;
385 	}
386 
387 	down_read(&qm->qps_lock);
388 
389 	if (qm->eqe && !strcmp(name, "EQE")) {
390 		xeqe = qm->eqe + xeqe_id;
391 	} else if (qm->aeqe && !strcmp(name, "AEQE")) {
392 		xeqe = qm->aeqe + xeqe_id;
393 	} else {
394 		ret = -EINVAL;
395 		goto err_unlock;
396 	}
397 
398 	dump_show(qm, xeqe, size, name);
399 
400 err_unlock:
401 	up_read(&qm->qps_lock);
402 	return ret;
403 }
404 
405 static int qm_dbg_help(struct hisi_qm *qm, char *s)
406 {
407 	struct device *dev = &qm->pdev->dev;
408 
409 	if (strsep(&s, " ")) {
410 		dev_err(dev, "Please do not input extra characters!\n");
411 		return -EINVAL;
412 	}
413 
414 	dev_info(dev, "available commands:\n");
415 	dev_info(dev, "sqc <num>\n");
416 	dev_info(dev, "cqc <num>\n");
417 	dev_info(dev, "eqc\n");
418 	dev_info(dev, "aeqc\n");
419 	dev_info(dev, "sq <num> <e>\n");
420 	dev_info(dev, "cq <num> <e>\n");
421 	dev_info(dev, "eq <e>\n");
422 	dev_info(dev, "aeq <e>\n");
423 
424 	return 0;
425 }
426 
427 static const struct qm_cmd_dump_item qm_cmd_dump_table[] = {
428 	{
429 		.cmd = "sqc",
430 		.info_name = "SQC",
431 		.dump_fn = qm_sqc_dump,
432 	}, {
433 		.cmd = "cqc",
434 		.info_name = "CQC",
435 		.dump_fn = qm_cqc_dump,
436 	}, {
437 		.cmd = "eqc",
438 		.info_name = "EQC",
439 		.dump_fn = qm_eqc_aeqc_dump,
440 	}, {
441 		.cmd = "aeqc",
442 		.info_name = "AEQC",
443 		.dump_fn = qm_eqc_aeqc_dump,
444 	}, {
445 		.cmd = "sq",
446 		.info_name = "SQE",
447 		.dump_fn = qm_sq_dump,
448 	}, {
449 		.cmd = "cq",
450 		.info_name = "CQE",
451 		.dump_fn = qm_cq_dump,
452 	}, {
453 		.cmd = "eq",
454 		.info_name = "EQE",
455 		.dump_fn = qm_eq_aeq_dump,
456 	}, {
457 		.cmd = "aeq",
458 		.info_name = "AEQE",
459 		.dump_fn = qm_eq_aeq_dump,
460 	},
461 };
462 
463 static int qm_cmd_write_dump(struct hisi_qm *qm, const char *cmd_buf)
464 {
465 	struct device *dev = &qm->pdev->dev;
466 	char *presult, *s, *s_tmp;
467 	int table_size, i, ret;
468 
469 	s = kstrdup(cmd_buf, GFP_KERNEL);
470 	if (!s)
471 		return -ENOMEM;
472 
473 	s_tmp = s;
474 	presult = strsep(&s, " ");
475 	if (!presult) {
476 		ret = -EINVAL;
477 		goto err_buffer_free;
478 	}
479 
480 	if (!strcmp(presult, "help")) {
481 		ret = qm_dbg_help(qm, s);
482 		goto err_buffer_free;
483 	}
484 
485 	table_size = ARRAY_SIZE(qm_cmd_dump_table);
486 	for (i = 0; i < table_size; i++) {
487 		if (!strcmp(presult, qm_cmd_dump_table[i].cmd)) {
488 			ret = qm_cmd_dump_table[i].dump_fn(qm, s,
489 				qm_cmd_dump_table[i].info_name);
490 			break;
491 		}
492 	}
493 
494 	if (i == table_size) {
495 		dev_info(dev, "Please echo help\n");
496 		ret = -EINVAL;
497 	}
498 
499 err_buffer_free:
500 	kfree(s_tmp);
501 
502 	return ret;
503 }
504 
505 static ssize_t qm_cmd_write(struct file *filp, const char __user *buffer,
506 			    size_t count, loff_t *pos)
507 {
508 	struct hisi_qm *qm = filp->private_data;
509 	char *cmd_buf, *cmd_buf_tmp;
510 	int ret;
511 
512 	if (*pos)
513 		return 0;
514 
515 	ret = hisi_qm_get_dfx_access(qm);
516 	if (ret)
517 		return ret;
518 
519 	/* Judge if the instance is being reset. */
520 	if (unlikely(atomic_read(&qm->status.flags) == QM_STOP)) {
521 		ret = 0;
522 		goto put_dfx_access;
523 	}
524 
525 	if (count > QM_DBG_WRITE_LEN) {
526 		ret = -ENOSPC;
527 		goto put_dfx_access;
528 	}
529 
530 	cmd_buf = memdup_user_nul(buffer, count);
531 	if (IS_ERR(cmd_buf)) {
532 		ret = PTR_ERR(cmd_buf);
533 		goto put_dfx_access;
534 	}
535 
536 	cmd_buf_tmp = strchr(cmd_buf, '\n');
537 	if (cmd_buf_tmp) {
538 		*cmd_buf_tmp = '\0';
539 		count = cmd_buf_tmp - cmd_buf + 1;
540 	}
541 
542 	ret = qm_cmd_write_dump(qm, cmd_buf);
543 	if (ret) {
544 		kfree(cmd_buf);
545 		goto put_dfx_access;
546 	}
547 
548 	kfree(cmd_buf);
549 
550 	ret = count;
551 
552 put_dfx_access:
553 	hisi_qm_put_dfx_access(qm);
554 	return ret;
555 }
556 
557 static const struct file_operations qm_cmd_fops = {
558 	.owner = THIS_MODULE,
559 	.open = simple_open,
560 	.read = qm_cmd_read,
561 	.write = qm_cmd_write,
562 };
563 
564 /**
565  * hisi_qm_regs_dump() - Dump registers's value.
566  * @s: debugfs file handle.
567  * @regset: accelerator registers information.
568  *
569  * Dump accelerator registers.
570  */
571 void hisi_qm_regs_dump(struct seq_file *s, struct debugfs_regset32 *regset)
572 {
573 	struct pci_dev *pdev = to_pci_dev(regset->dev);
574 	struct hisi_qm *qm = pci_get_drvdata(pdev);
575 	const struct debugfs_reg32 *regs = regset->regs;
576 	int regs_len = regset->nregs;
577 	int i, ret;
578 	u32 val;
579 
580 	ret = hisi_qm_get_dfx_access(qm);
581 	if (ret)
582 		return;
583 
584 	for (i = 0; i < regs_len; i++) {
585 		val = readl(regset->base + regs[i].offset);
586 		seq_printf(s, "%s= 0x%08x\n", regs[i].name, val);
587 	}
588 
589 	hisi_qm_put_dfx_access(qm);
590 }
591 EXPORT_SYMBOL_GPL(hisi_qm_regs_dump);
592 
593 static int qm_regs_show(struct seq_file *s, void *unused)
594 {
595 	struct hisi_qm *qm = s->private;
596 	struct debugfs_regset32 regset;
597 
598 	if (qm->fun_type == QM_HW_PF) {
599 		regset.regs = qm_dfx_regs;
600 		regset.nregs = ARRAY_SIZE(qm_dfx_regs);
601 	} else {
602 		regset.regs = qm_vf_dfx_regs;
603 		regset.nregs = ARRAY_SIZE(qm_vf_dfx_regs);
604 	}
605 
606 	regset.base = qm->io_base;
607 	regset.dev = &qm->pdev->dev;
608 
609 	hisi_qm_regs_dump(s, &regset);
610 
611 	return 0;
612 }
613 
614 DEFINE_SHOW_ATTRIBUTE(qm_regs);
615 
616 static u32 current_q_read(struct hisi_qm *qm)
617 {
618 	return readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) >> QM_DFX_QN_SHIFT;
619 }
620 
621 static int current_q_write(struct hisi_qm *qm, u32 val)
622 {
623 	u32 tmp;
624 
625 	if (val >= qm->debug.curr_qm_qp_num)
626 		return -EINVAL;
627 
628 	tmp = val << QM_DFX_QN_SHIFT |
629 	      (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_FUN_MASK);
630 	writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
631 
632 	tmp = val << QM_DFX_QN_SHIFT |
633 	      (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_FUN_MASK);
634 	writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
635 
636 	return 0;
637 }
638 
639 static u32 clear_enable_read(struct hisi_qm *qm)
640 {
641 	return readl(qm->io_base + QM_DFX_CNT_CLR_CE);
642 }
643 
644 /* rd_clr_ctrl 1 enable read clear, otherwise 0 disable it */
645 static int clear_enable_write(struct hisi_qm *qm, u32 rd_clr_ctrl)
646 {
647 	if (rd_clr_ctrl > 1)
648 		return -EINVAL;
649 
650 	writel(rd_clr_ctrl, qm->io_base + QM_DFX_CNT_CLR_CE);
651 
652 	return 0;
653 }
654 
655 static u32 current_qm_read(struct hisi_qm *qm)
656 {
657 	return readl(qm->io_base + QM_DFX_MB_CNT_VF);
658 }
659 
660 static int qm_get_vf_qp_num(struct hisi_qm *qm, u32 fun_num)
661 {
662 	u32 remain_q_num, vfq_num;
663 	u32 num_vfs = qm->vfs_num;
664 
665 	vfq_num = (qm->ctrl_qp_num - qm->qp_num) / num_vfs;
666 	if (vfq_num >= qm->max_qp_num)
667 		return qm->max_qp_num;
668 
669 	remain_q_num = (qm->ctrl_qp_num - qm->qp_num) % num_vfs;
670 	if (vfq_num + remain_q_num <= qm->max_qp_num)
671 		return fun_num == num_vfs ? vfq_num + remain_q_num : vfq_num;
672 
673 	/*
674 	 * if vfq_num + remain_q_num > max_qp_num, the last VFs,
675 	 * each with one more queue.
676 	 */
677 	return fun_num + remain_q_num > num_vfs ? vfq_num + 1 : vfq_num;
678 }
679 
680 static int current_qm_write(struct hisi_qm *qm, u32 val)
681 {
682 	u32 tmp;
683 
684 	if (val > qm->vfs_num)
685 		return -EINVAL;
686 
687 	/* According PF or VF Dev ID to calculation curr_qm_qp_num and store */
688 	if (!val)
689 		qm->debug.curr_qm_qp_num = qm->qp_num;
690 	else
691 		qm->debug.curr_qm_qp_num = qm_get_vf_qp_num(qm, val);
692 
693 	writel(val, qm->io_base + QM_DFX_MB_CNT_VF);
694 	writel(val, qm->io_base + QM_DFX_DB_CNT_VF);
695 
696 	tmp = val |
697 	      (readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) & CURRENT_Q_MASK);
698 	writel(tmp, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
699 
700 	tmp = val |
701 	      (readl(qm->io_base + QM_DFX_CQE_CNT_VF_CQN) & CURRENT_Q_MASK);
702 	writel(tmp, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
703 
704 	return 0;
705 }
706 
707 static ssize_t qm_debug_read(struct file *filp, char __user *buf,
708 			     size_t count, loff_t *pos)
709 {
710 	struct debugfs_file *file = filp->private_data;
711 	enum qm_debug_file index = file->index;
712 	struct hisi_qm *qm = file_to_qm(file);
713 	char tbuf[QM_DBG_TMP_BUF_LEN];
714 	u32 val;
715 	int ret;
716 
717 	ret = hisi_qm_get_dfx_access(qm);
718 	if (ret)
719 		return ret;
720 
721 	mutex_lock(&file->lock);
722 	switch (index) {
723 	case CURRENT_QM:
724 		val = current_qm_read(qm);
725 		break;
726 	case CURRENT_Q:
727 		val = current_q_read(qm);
728 		break;
729 	case CLEAR_ENABLE:
730 		val = clear_enable_read(qm);
731 		break;
732 	default:
733 		goto err_input;
734 	}
735 	mutex_unlock(&file->lock);
736 
737 	hisi_qm_put_dfx_access(qm);
738 	ret = scnprintf(tbuf, QM_DBG_TMP_BUF_LEN, "%u\n", val);
739 	return simple_read_from_buffer(buf, count, pos, tbuf, ret);
740 
741 err_input:
742 	mutex_unlock(&file->lock);
743 	hisi_qm_put_dfx_access(qm);
744 	return -EINVAL;
745 }
746 
747 static ssize_t qm_debug_write(struct file *filp, const char __user *buf,
748 			      size_t count, loff_t *pos)
749 {
750 	struct debugfs_file *file = filp->private_data;
751 	enum qm_debug_file index = file->index;
752 	struct hisi_qm *qm = file_to_qm(file);
753 	unsigned long val;
754 	char tbuf[QM_DBG_TMP_BUF_LEN];
755 	int len, ret;
756 
757 	if (*pos != 0)
758 		return 0;
759 
760 	if (count >= QM_DBG_TMP_BUF_LEN)
761 		return -ENOSPC;
762 
763 	len = simple_write_to_buffer(tbuf, QM_DBG_TMP_BUF_LEN - 1, pos, buf,
764 				     count);
765 	if (len < 0)
766 		return len;
767 
768 	tbuf[len] = '\0';
769 	if (kstrtoul(tbuf, 0, &val))
770 		return -EFAULT;
771 
772 	ret = hisi_qm_get_dfx_access(qm);
773 	if (ret)
774 		return ret;
775 
776 	mutex_lock(&file->lock);
777 	switch (index) {
778 	case CURRENT_QM:
779 		ret = current_qm_write(qm, val);
780 		break;
781 	case CURRENT_Q:
782 		ret = current_q_write(qm, val);
783 		break;
784 	case CLEAR_ENABLE:
785 		ret = clear_enable_write(qm, val);
786 		break;
787 	default:
788 		ret = -EINVAL;
789 	}
790 	mutex_unlock(&file->lock);
791 
792 	hisi_qm_put_dfx_access(qm);
793 
794 	if (ret)
795 		return ret;
796 
797 	return count;
798 }
799 
800 static const struct file_operations qm_debug_fops = {
801 	.owner = THIS_MODULE,
802 	.open = simple_open,
803 	.read = qm_debug_read,
804 	.write = qm_debug_write,
805 };
806 
807 static void dfx_regs_uninit(struct hisi_qm *qm,
808 		struct dfx_diff_registers *dregs, int reg_len)
809 {
810 	int i;
811 
812 	/* Setting the pointer is NULL to prevent double free */
813 	for (i = 0; i < reg_len; i++) {
814 		kfree(dregs[i].regs);
815 		dregs[i].regs = NULL;
816 	}
817 	kfree(dregs);
818 }
819 
820 static struct dfx_diff_registers *dfx_regs_init(struct hisi_qm *qm,
821 	const struct dfx_diff_registers *cregs, u32 reg_len)
822 {
823 	struct dfx_diff_registers *diff_regs;
824 	u32 j, base_offset;
825 	int i;
826 
827 	diff_regs = kcalloc(reg_len, sizeof(*diff_regs), GFP_KERNEL);
828 	if (!diff_regs)
829 		return ERR_PTR(-ENOMEM);
830 
831 	for (i = 0; i < reg_len; i++) {
832 		if (!cregs[i].reg_len)
833 			continue;
834 
835 		diff_regs[i].reg_offset = cregs[i].reg_offset;
836 		diff_regs[i].reg_len = cregs[i].reg_len;
837 		diff_regs[i].regs = kcalloc(QM_DFX_REGS_LEN, cregs[i].reg_len,
838 					 GFP_KERNEL);
839 		if (!diff_regs[i].regs)
840 			goto alloc_error;
841 
842 		for (j = 0; j < diff_regs[i].reg_len; j++) {
843 			base_offset = diff_regs[i].reg_offset +
844 					j * QM_DFX_REGS_LEN;
845 			diff_regs[i].regs[j] = readl(qm->io_base + base_offset);
846 		}
847 	}
848 
849 	return diff_regs;
850 
851 alloc_error:
852 	while (i > 0) {
853 		i--;
854 		kfree(diff_regs[i].regs);
855 	}
856 	kfree(diff_regs);
857 	return ERR_PTR(-ENOMEM);
858 }
859 
860 static int qm_diff_regs_init(struct hisi_qm *qm,
861 		struct dfx_diff_registers *dregs, u32 reg_len)
862 {
863 	qm->debug.qm_diff_regs = dfx_regs_init(qm, qm_diff_regs, ARRAY_SIZE(qm_diff_regs));
864 	if (IS_ERR(qm->debug.qm_diff_regs))
865 		return PTR_ERR(qm->debug.qm_diff_regs);
866 
867 	qm->debug.acc_diff_regs = dfx_regs_init(qm, dregs, reg_len);
868 	if (IS_ERR(qm->debug.acc_diff_regs)) {
869 		dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs));
870 		return PTR_ERR(qm->debug.acc_diff_regs);
871 	}
872 
873 	return 0;
874 }
875 
876 static void qm_last_regs_uninit(struct hisi_qm *qm)
877 {
878 	struct qm_debug *debug = &qm->debug;
879 
880 	if (qm->fun_type == QM_HW_VF || !debug->qm_last_words)
881 		return;
882 
883 	kfree(debug->qm_last_words);
884 	debug->qm_last_words = NULL;
885 }
886 
887 static int qm_last_regs_init(struct hisi_qm *qm)
888 {
889 	int dfx_regs_num = ARRAY_SIZE(qm_dfx_regs);
890 	struct qm_debug *debug = &qm->debug;
891 	int i;
892 
893 	if (qm->fun_type == QM_HW_VF)
894 		return 0;
895 
896 	debug->qm_last_words = kcalloc(dfx_regs_num, sizeof(unsigned int), GFP_KERNEL);
897 	if (!debug->qm_last_words)
898 		return -ENOMEM;
899 
900 	for (i = 0; i < dfx_regs_num; i++) {
901 		debug->qm_last_words[i] = readl_relaxed(qm->io_base +
902 			qm_dfx_regs[i].offset);
903 	}
904 
905 	return 0;
906 }
907 
908 static void qm_diff_regs_uninit(struct hisi_qm *qm, u32 reg_len)
909 {
910 	dfx_regs_uninit(qm, qm->debug.acc_diff_regs, reg_len);
911 	dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs));
912 }
913 
914 /**
915  * hisi_qm_regs_debugfs_init() - Allocate memory for registers.
916  * @qm: device qm handle.
917  * @dregs: diff registers handle.
918  * @reg_len: diff registers region length.
919  */
920 int hisi_qm_regs_debugfs_init(struct hisi_qm *qm,
921 		struct dfx_diff_registers *dregs, u32 reg_len)
922 {
923 	int ret;
924 
925 	if (!qm || !dregs)
926 		return -EINVAL;
927 
928 	if (qm->fun_type != QM_HW_PF)
929 		return 0;
930 
931 	ret = qm_last_regs_init(qm);
932 	if (ret) {
933 		dev_info(&qm->pdev->dev, "failed to init qm words memory!\n");
934 		return ret;
935 	}
936 
937 	ret = qm_diff_regs_init(qm, dregs, reg_len);
938 	if (ret) {
939 		qm_last_regs_uninit(qm);
940 		return ret;
941 	}
942 
943 	return 0;
944 }
945 EXPORT_SYMBOL_GPL(hisi_qm_regs_debugfs_init);
946 
947 /**
948  * hisi_qm_regs_debugfs_uninit() - Free memory for registers.
949  * @qm: device qm handle.
950  * @reg_len: diff registers region length.
951  */
952 void hisi_qm_regs_debugfs_uninit(struct hisi_qm *qm, u32 reg_len)
953 {
954 	if (!qm || qm->fun_type != QM_HW_PF)
955 		return;
956 
957 	qm_diff_regs_uninit(qm, reg_len);
958 	qm_last_regs_uninit(qm);
959 }
960 EXPORT_SYMBOL_GPL(hisi_qm_regs_debugfs_uninit);
961 
962 /**
963  * hisi_qm_acc_diff_regs_dump() - Dump registers's value.
964  * @qm: device qm handle.
965  * @s: Debugfs file handle.
966  * @dregs: diff registers handle.
967  * @regs_len: diff registers region length.
968  */
969 void hisi_qm_acc_diff_regs_dump(struct hisi_qm *qm, struct seq_file *s,
970 	struct dfx_diff_registers *dregs, u32 regs_len)
971 {
972 	u32 j, val, base_offset;
973 	int i, ret;
974 
975 	if (!qm || !s || !dregs)
976 		return;
977 
978 	ret = hisi_qm_get_dfx_access(qm);
979 	if (ret)
980 		return;
981 
982 	down_read(&qm->qps_lock);
983 	for (i = 0; i < regs_len; i++) {
984 		if (!dregs[i].reg_len)
985 			continue;
986 
987 		for (j = 0; j < dregs[i].reg_len; j++) {
988 			base_offset = dregs[i].reg_offset + j * QM_DFX_REGS_LEN;
989 			val = readl(qm->io_base + base_offset);
990 			if (val != dregs[i].regs[j])
991 				seq_printf(s, "0x%08x = 0x%08x ---> 0x%08x\n",
992 					   base_offset, dregs[i].regs[j], val);
993 		}
994 	}
995 	up_read(&qm->qps_lock);
996 
997 	hisi_qm_put_dfx_access(qm);
998 }
999 EXPORT_SYMBOL_GPL(hisi_qm_acc_diff_regs_dump);
1000 
1001 void hisi_qm_show_last_dfx_regs(struct hisi_qm *qm)
1002 {
1003 	struct qm_debug *debug = &qm->debug;
1004 	struct pci_dev *pdev = qm->pdev;
1005 	u32 val;
1006 	int i;
1007 
1008 	if (qm->fun_type == QM_HW_VF || !debug->qm_last_words)
1009 		return;
1010 
1011 	for (i = 0; i < ARRAY_SIZE(qm_dfx_regs); i++) {
1012 		val = readl_relaxed(qm->io_base + qm_dfx_regs[i].offset);
1013 		if (debug->qm_last_words[i] != val)
1014 			pci_info(pdev, "%s \t= 0x%08x => 0x%08x\n",
1015 			qm_dfx_regs[i].name, debug->qm_last_words[i], val);
1016 	}
1017 }
1018 
1019 static int qm_diff_regs_show(struct seq_file *s, void *unused)
1020 {
1021 	struct hisi_qm *qm = s->private;
1022 
1023 	hisi_qm_acc_diff_regs_dump(qm, s, qm->debug.qm_diff_regs,
1024 					ARRAY_SIZE(qm_diff_regs));
1025 
1026 	return 0;
1027 }
1028 DEFINE_SHOW_ATTRIBUTE(qm_diff_regs);
1029 
1030 static int qm_state_show(struct seq_file *s, void *unused)
1031 {
1032 	struct hisi_qm *qm = s->private;
1033 	u32 val;
1034 	int ret;
1035 
1036 	/* If device is in suspended, directly return the idle state. */
1037 	ret = hisi_qm_get_dfx_access(qm);
1038 	if (!ret) {
1039 		val = readl(qm->io_base + QM_IN_IDLE_ST_REG);
1040 		hisi_qm_put_dfx_access(qm);
1041 	} else if (ret == -EAGAIN) {
1042 		val = QM_IN_IDLE_STATE;
1043 	} else {
1044 		return ret;
1045 	}
1046 
1047 	seq_printf(s, "%u\n", val);
1048 
1049 	return 0;
1050 }
1051 
1052 DEFINE_SHOW_ATTRIBUTE(qm_state);
1053 
1054 static ssize_t qm_status_read(struct file *filp, char __user *buffer,
1055 			      size_t count, loff_t *pos)
1056 {
1057 	struct hisi_qm *qm = filp->private_data;
1058 	char buf[QM_DBG_READ_LEN];
1059 	int val, len;
1060 
1061 	val = atomic_read(&qm->status.flags);
1062 	len = scnprintf(buf, QM_DBG_READ_LEN, "%s\n", qm_s[val]);
1063 
1064 	return simple_read_from_buffer(buffer, count, pos, buf, len);
1065 }
1066 
1067 static const struct file_operations qm_status_fops = {
1068 	.owner = THIS_MODULE,
1069 	.open = simple_open,
1070 	.read = qm_status_read,
1071 };
1072 
1073 static void qm_create_debugfs_file(struct hisi_qm *qm, struct dentry *dir,
1074 				   enum qm_debug_file index)
1075 {
1076 	struct debugfs_file *file = qm->debug.files + index;
1077 
1078 	debugfs_create_file(qm_debug_file_name[index], 0600, dir, file,
1079 			    &qm_debug_fops);
1080 
1081 	file->index = index;
1082 	mutex_init(&file->lock);
1083 	file->debug = &qm->debug;
1084 }
1085 
1086 static int qm_debugfs_atomic64_set(void *data, u64 val)
1087 {
1088 	if (val)
1089 		return -EINVAL;
1090 
1091 	atomic64_set((atomic64_t *)data, 0);
1092 
1093 	return 0;
1094 }
1095 
1096 static int qm_debugfs_atomic64_get(void *data, u64 *val)
1097 {
1098 	*val = atomic64_read((atomic64_t *)data);
1099 
1100 	return 0;
1101 }
1102 
1103 DEFINE_DEBUGFS_ATTRIBUTE(qm_atomic64_ops, qm_debugfs_atomic64_get,
1104 			 qm_debugfs_atomic64_set, "%llu\n");
1105 
1106 /**
1107  * hisi_qm_debug_init() - Initialize qm related debugfs files.
1108  * @qm: The qm for which we want to add debugfs files.
1109  *
1110  * Create qm related debugfs files.
1111  */
1112 void hisi_qm_debug_init(struct hisi_qm *qm)
1113 {
1114 	struct dfx_diff_registers *qm_regs = qm->debug.qm_diff_regs;
1115 	struct qm_dev_dfx *dev_dfx = &qm->debug.dev_dfx;
1116 	struct qm_dfx *dfx = &qm->debug.dfx;
1117 	struct dentry *qm_d;
1118 	void *data;
1119 	int i;
1120 
1121 	qm_d = debugfs_create_dir("qm", qm->debug.debug_root);
1122 	qm->debug.qm_d = qm_d;
1123 
1124 	/* only show this in PF */
1125 	if (qm->fun_type == QM_HW_PF) {
1126 		debugfs_create_file("qm_state", 0444, qm->debug.qm_d,
1127 					qm, &qm_state_fops);
1128 
1129 		qm_create_debugfs_file(qm, qm->debug.debug_root, CURRENT_QM);
1130 		for (i = CURRENT_Q; i < DEBUG_FILE_NUM; i++)
1131 			qm_create_debugfs_file(qm, qm->debug.qm_d, i);
1132 	}
1133 
1134 	if (qm_regs)
1135 		debugfs_create_file("diff_regs", 0444, qm->debug.qm_d,
1136 					qm, &qm_diff_regs_fops);
1137 
1138 	debugfs_create_file("regs", 0444, qm->debug.qm_d, qm, &qm_regs_fops);
1139 
1140 	debugfs_create_file("cmd", 0600, qm->debug.qm_d, qm, &qm_cmd_fops);
1141 
1142 	debugfs_create_file("status", 0444, qm->debug.qm_d, qm,
1143 			&qm_status_fops);
1144 
1145 	debugfs_create_u32("dev_state", 0444, qm->debug.qm_d, &dev_dfx->dev_state);
1146 	debugfs_create_u32("dev_timeout", 0644, qm->debug.qm_d, &dev_dfx->dev_timeout);
1147 
1148 	for (i = 0; i < ARRAY_SIZE(qm_dfx_files); i++) {
1149 		data = (atomic64_t *)((uintptr_t)dfx + qm_dfx_files[i].offset);
1150 		debugfs_create_file(qm_dfx_files[i].name,
1151 			0644,
1152 			qm_d,
1153 			data,
1154 			&qm_atomic64_ops);
1155 	}
1156 
1157 	if (test_bit(QM_SUPPORT_FUNC_QOS, &qm->caps))
1158 		hisi_qm_set_algqos_init(qm);
1159 }
1160 EXPORT_SYMBOL_GPL(hisi_qm_debug_init);
1161 
1162 /**
1163  * hisi_qm_debug_regs_clear() - clear qm debug related registers.
1164  * @qm: The qm for which we want to clear its debug registers.
1165  */
1166 void hisi_qm_debug_regs_clear(struct hisi_qm *qm)
1167 {
1168 	const struct debugfs_reg32 *regs;
1169 	int i;
1170 
1171 	/* clear current_qm */
1172 	writel(0x0, qm->io_base + QM_DFX_MB_CNT_VF);
1173 	writel(0x0, qm->io_base + QM_DFX_DB_CNT_VF);
1174 
1175 	/* clear current_q */
1176 	writel(0x0, qm->io_base + QM_DFX_SQE_CNT_VF_SQN);
1177 	writel(0x0, qm->io_base + QM_DFX_CQE_CNT_VF_CQN);
1178 
1179 	/*
1180 	 * these registers are reading and clearing, so clear them after
1181 	 * reading them.
1182 	 */
1183 	writel(0x1, qm->io_base + QM_DFX_CNT_CLR_CE);
1184 
1185 	regs = qm_dfx_regs;
1186 	for (i = 0; i < CNT_CYC_REGS_NUM; i++) {
1187 		readl(qm->io_base + regs->offset);
1188 		regs++;
1189 	}
1190 
1191 	/* clear clear_enable */
1192 	writel(0x0, qm->io_base + QM_DFX_CNT_CLR_CE);
1193 }
1194 EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
1195