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