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
30static const char * const qm_debug_file_name[] = {
31	[CURRENT_QM]   = "current_qm",
32	[CURRENT_Q]    = "current_q",
33	[CLEAR_ENABLE] = "clear_enable",
34};
35
36static const char * const qm_s[] = {
37	"work", "stop",
38};
39
40struct qm_dfx_item {
41	const char *name;
42	u32 offset;
43};
44
45struct 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
51static 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
60static 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
112static 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 */
117static 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
133static 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
140static 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
152static 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
167static 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
202static 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
237static 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
271static 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
311static 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
340static 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
358static 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
400err_unlock:
401	up_read(&qm->qps_lock);
402	return ret;
403}
404
405static 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
427static 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
463static 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
499err_buffer_free:
500	kfree(s_tmp);
501
502	return ret;
503}
504
505static 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
552put_dfx_access:
553	hisi_qm_put_dfx_access(qm);
554	return ret;
555}
556
557static 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 */
571void 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}
591EXPORT_SYMBOL_GPL(hisi_qm_regs_dump);
592
593static 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
614DEFINE_SHOW_ATTRIBUTE(qm_regs);
615
616static 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
621static 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
639static 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 */
645static 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
655static u32 current_qm_read(struct hisi_qm *qm)
656{
657	return readl(qm->io_base + QM_DFX_MB_CNT_VF);
658}
659
660static 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
680static 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
707static 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
741err_input:
742	mutex_unlock(&file->lock);
743	hisi_qm_put_dfx_access(qm);
744	return -EINVAL;
745}
746
747static 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
800static 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
807static 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
820static 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
851alloc_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
860static 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
876static 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
887static 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
908static 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 */
920int 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}
945EXPORT_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 */
952void 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}
960EXPORT_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 */
969void 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}
999EXPORT_SYMBOL_GPL(hisi_qm_acc_diff_regs_dump);
1000
1001void 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
1019static 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}
1028DEFINE_SHOW_ATTRIBUTE(qm_diff_regs);
1029
1030static 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
1052DEFINE_SHOW_ATTRIBUTE(qm_state);
1053
1054static 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
1067static const struct file_operations qm_status_fops = {
1068	.owner = THIS_MODULE,
1069	.open = simple_open,
1070	.read = qm_status_read,
1071};
1072
1073static 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
1086static 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
1096static int qm_debugfs_atomic64_get(void *data, u64 *val)
1097{
1098	*val = atomic64_read((atomic64_t *)data);
1099
1100	return 0;
1101}
1102
1103DEFINE_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 */
1112void 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}
1160EXPORT_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 */
1166void 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}
1194EXPORT_SYMBOL_GPL(hisi_qm_debug_regs_clear);
1195