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