// SPDX-License-Identifier: GPL-2.0/* Copyright (c) 2022 HiSilicon Limited. */#include <linux/hisi_acc_qm.h>#include "qm_common.h" #define QM_DFX_BASE 0x0100000#define QM_DFX_STATE1 0x0104000#define QM_DFX_STATE2 0x01040C8#define QM_DFX_COMMON 0x0000#define QM_DFX_BASE_LEN 0x5A#define QM_DFX_STATE1_LEN 0x2E#define QM_DFX_STATE2_LEN 0x11#define QM_DFX_COMMON_LEN 0xC3#define QM_DFX_REGS_LEN 4UL#define QM_DBG_TMP_BUF_LEN 22#define QM_XQC_ADDR_MASK GENMASK(31, 0)#define CURRENT_FUN_MASK GENMASK(5, 0)#define CURRENT_Q_MASK GENMASK(31, 16)#define QM_SQE_ADDR_MASK GENMASK(7, 0) #define QM_DFX_MB_CNT_VF 0x104010#define QM_DFX_DB_CNT_VF 0x104020#define QM_DFX_SQE_CNT_VF_SQN 0x104030#define QM_DFX_CQE_CNT_VF_CQN 0x104040#define QM_DFX_QN_SHIFT 16#define QM_DFX_CNT_CLR_CE 0x100118#define QM_DBG_WRITE_LEN 1024#define QM_IN_IDLE_ST_REG 0x1040e4#define QM_IN_IDLE_STATE 0x1 static const char * const qm_debug_file_name[] = { [CURRENT_QM] = "current_qm", [CURRENT_Q] = "current_q", [CLEAR_ENABLE] = "clear_enable",}; static const char * const qm_s[] = { "work", "stop",}; struct qm_dfx_item { const char *name; u32 offset;}; struct qm_cmd_dump_item { const char *cmd; const char *info_name; int (*dump_fn)(struct hisi_qm *qm, char *cmd, const char *info_name);}; static struct qm_dfx_item qm_dfx_files[] = { {"err_irq", offsetof(struct qm_dfx, err_irq_cnt)}, {"aeq_irq", offsetof(struct qm_dfx, aeq_irq_cnt)}, {"abnormal_irq", offsetof(struct qm_dfx, abnormal_irq_cnt)}, {"create_qp_err", offsetof(struct qm_dfx, create_qp_err_cnt)}, {"mb_err", offsetof(struct qm_dfx, mb_err_cnt)},}; #define CNT_CYC_REGS_NUM 10static const struct debugfs_reg32 qm_dfx_regs[] = { /* XXX_CNT are reading clear register */ {"QM_ECC_1BIT_CNT ", 0x104000}, {"QM_ECC_MBIT_CNT ", 0x104008}, {"QM_DFX_MB_CNT ", 0x104018}, {"QM_DFX_DB_CNT ", 0x104028}, {"QM_DFX_SQE_CNT ", 0x104038}, {"QM_DFX_CQE_CNT ", 0x104048}, {"QM_DFX_SEND_SQE_TO_ACC_CNT ", 0x104050}, {"QM_DFX_WB_SQE_FROM_ACC_CNT ", 0x104058}, {"QM_DFX_ACC_FINISH_CNT ", 0x104060}, {"QM_DFX_CQE_ERR_CNT ", 0x1040b4}, {"QM_DFX_FUNS_ACTIVE_ST ", 0x200}, {"QM_ECC_1BIT_INF ", 0x104004}, {"QM_ECC_MBIT_INF ", 0x10400c}, {"QM_DFX_ACC_RDY_VLD0 ", 0x1040a0}, {"QM_DFX_ACC_RDY_VLD1 ", 0x1040a4}, {"QM_DFX_AXI_RDY_VLD ", 0x1040a8}, {"QM_DFX_FF_ST0 ", 0x1040c8}, {"QM_DFX_FF_ST1 ", 0x1040cc}, {"QM_DFX_FF_ST2 ", 0x1040d0}, {"QM_DFX_FF_ST3 ", 0x1040d4}, {"QM_DFX_FF_ST4 ", 0x1040d8}, {"QM_DFX_FF_ST5 ", 0x1040dc}, {"QM_DFX_FF_ST6 ", 0x1040e0}, {"QM_IN_IDLE_ST ", 0x1040e4}, {"QM_CACHE_CTL ", 0x100050}, {"QM_TIMEOUT_CFG ", 0x100070}, {"QM_DB_TIMEOUT_CFG ", 0x100074}, {"QM_FLR_PENDING_TIME_CFG ", 0x100078}, {"QM_ARUSR_MCFG1 ", 0x100088}, {"QM_AWUSR_MCFG1 ", 0x100098}, {"QM_AXI_M_CFG_ENABLE ", 0x1000B0}, {"QM_RAS_CE_THRESHOLD ", 0x1000F8}, {"QM_AXI_TIMEOUT_CTRL ", 0x100120}, {"QM_AXI_TIMEOUT_STATUS ", 0x100124}, {"QM_CQE_AGGR_TIMEOUT_CTRL ", 0x100144}, {"ACC_RAS_MSI_INT_SEL ", 0x1040fc}, {"QM_CQE_OUT ", 0x104100}, {"QM_EQE_OUT ", 0x104104}, {"QM_AEQE_OUT ", 0x104108}, {"QM_DB_INFO0 ", 0x104180}, {"QM_DB_INFO1 ", 0x104184}, {"QM_AM_CTRL_GLOBAL ", 0x300000}, {"QM_AM_CURR_PORT_STS ", 0x300100}, {"QM_AM_CURR_TRANS_RETURN ", 0x300150}, {"QM_AM_CURR_RD_MAX_TXID ", 0x300154}, {"QM_AM_CURR_WR_MAX_TXID ", 0x300158}, {"QM_AM_ALARM_RRESP ", 0x300180}, {"QM_AM_ALARM_BRESP ", 0x300184},}; static const struct debugfs_reg32 qm_vf_dfx_regs[] = { {"QM_DFX_FUNS_ACTIVE_ST ", 0x200},}; /* define the QM's dfx regs region and region length */static struct dfx_diff_registers qm_diff_regs[] = { { .reg_offset = QM_DFX_BASE, .reg_len = QM_DFX_BASE_LEN, }, { .reg_offset = QM_DFX_STATE1, .reg_len = QM_DFX_STATE1_LEN, }, { .reg_offset = QM_DFX_STATE2, .reg_len = QM_DFX_STATE2_LEN, }, { .reg_offset = QM_DFX_COMMON, .reg_len = QM_DFX_COMMON_LEN, },}; static struct hisi_qm *file_to_qm(struct debugfs_file *file){ struct qm_debug *debug = file->debug; return container_of(debug, struct hisi_qm, debug);} static ssize_t qm_cmd_read(struct file *filp, char __user *buffer, size_t count, loff_t *pos){ char buf[QM_DBG_READ_LEN]; int len; len = scnprintf(buf, QM_DBG_READ_LEN, "%s\n", "Please echo help to cmd to get help information"); return simple_read_from_buffer(buffer, count, pos, buf, len);} static void dump_show(struct hisi_qm *qm, void *info, unsigned int info_size, const char *info_name){ struct device *dev = &qm->pdev->dev; u8 *info_curr = info; u32 i;#define BYTE_PER_DW 4 dev_info(dev, "%s DUMP\n", info_name); for (i = 0; i < info_size; i += BYTE_PER_DW, info_curr += BYTE_PER_DW) { pr_info("DW%u: %02X%02X %02X%02X\n", i / BYTE_PER_DW, *(info_curr + 3), *(info_curr + 2), *(info_curr + 1), *(info_curr)); }} static int qm_sqc_dump(struct hisi_qm *qm, char *s, const char *name){ struct device *dev = &qm->pdev->dev; struct qm_sqc sqc; u32 qp_id; int ret; if (!s) return -EINVAL; ret = kstrtou32(s, 0, &qp_id); if (ret || qp_id >= qm->qp_num) { dev_err(dev, "Please input qp num (0-%u)", qm->qp_num - 1); return -EINVAL; } ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp_id, 1); if (!ret) { sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &sqc, sizeof(struct qm_sqc), name); return 0; } down_read(&qm->qps_lock); if (qm->sqc) { memcpy(&sqc, qm->sqc + qp_id, sizeof(struct qm_sqc)); sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &sqc, sizeof(struct qm_sqc), "SOFT SQC"); } up_read(&qm->qps_lock); return 0;} static int qm_cqc_dump(struct hisi_qm *qm, char *s, const char *name){ struct device *dev = &qm->pdev->dev; struct qm_cqc cqc; u32 qp_id; int ret; if (!s) return -EINVAL; ret = kstrtou32(s, 0, &qp_id); if (ret || qp_id >= qm->qp_num) { dev_err(dev, "Please input qp num (0-%u)", qm->qp_num - 1); return -EINVAL; } ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp_id, 1); if (!ret) { cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &cqc, sizeof(struct qm_cqc), name); return 0; } down_read(&qm->qps_lock); if (qm->cqc) { memcpy(&cqc, qm->cqc + qp_id, sizeof(struct qm_cqc)); cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &cqc, sizeof(struct qm_cqc), "SOFT CQC"); } up_read(&qm->qps_lock); return 0;} static int qm_eqc_aeqc_dump(struct hisi_qm *qm, char *s, const char *name){ struct device *dev = &qm->pdev->dev; struct qm_aeqc aeqc; struct qm_eqc eqc; size_t size; void *xeqc; int ret; u8 cmd; if (strsep(&s, " ")) { dev_err(dev, "Please do not input extra characters!\n"); return -EINVAL; } if (!strcmp(name, "EQC")) { cmd = QM_MB_CMD_EQC; size = sizeof(struct qm_eqc); xeqc = &eqc; } else { cmd = QM_MB_CMD_AEQC; size = sizeof(struct qm_aeqc); xeqc = &aeqc; } ret = qm_set_and_get_xqc(qm, cmd, xeqc, 0, 1); if (ret) return ret; aeqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); aeqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); eqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); eqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, xeqc, size, name); return ret;} static int q_dump_param_parse(struct hisi_qm *qm, char *s, u32 *e_id, u32 *q_id, u16 q_depth){ struct device *dev = &qm->pdev->dev; unsigned int qp_num = qm->qp_num; char *presult; int ret; presult = strsep(&s, " "); if (!presult) { dev_err(dev, "Please input qp number!\n"); return -EINVAL; } ret = kstrtou32(presult, 0, q_id); if (ret || *q_id >= qp_num) { dev_err(dev, "Please input qp num (0-%u)", qp_num - 1); return -EINVAL; } presult = strsep(&s, " "); if (!presult) { dev_err(dev, "Please input sqe number!\n"); return -EINVAL; } ret = kstrtou32(presult, 0, e_id); if (ret || *e_id >= q_depth) { dev_err(dev, "Please input sqe num (0-%d)", q_depth - 1); return -EINVAL; } if (strsep(&s, " ")) { dev_err(dev, "Please do not input extra characters!\n"); return -EINVAL; } return 0;} static int qm_sq_dump(struct hisi_qm *qm, char *s, const char *name){ u16 sq_depth = qm->qp_array->sq_depth; struct hisi_qp *qp; u32 qp_id, sqe_id; void *sqe; int ret; ret = q_dump_param_parse(qm, s, &sqe_id, &qp_id, sq_depth); if (ret) return ret; sqe = kzalloc(qm->sqe_size, GFP_KERNEL); if (!sqe) return -ENOMEM; qp = &qm->qp_array[qp_id]; memcpy(sqe, qp->sqe + sqe_id * qm->sqe_size, qm->sqe_size); memset(sqe + qm->debug.sqe_mask_offset, QM_SQE_ADDR_MASK, qm->debug.sqe_mask_len); dump_show(qm, sqe, qm->sqe_size, name); kfree(sqe); return 0;} static int qm_cq_dump(struct hisi_qm *qm, char *s, const char *name){ struct qm_cqe *cqe_curr; struct hisi_qp *qp; u32 qp_id, cqe_id; int ret; ret = q_dump_param_parse(qm, s, &cqe_id, &qp_id, qm->qp_array->cq_depth); if (ret) return ret; qp = &qm->qp_array[qp_id]; cqe_curr = qp->cqe + cqe_id; dump_show(qm, cqe_curr, sizeof(struct qm_cqe), name); return 0;} static int qm_eq_aeq_dump(struct hisi_qm *qm, char *s, const char *name){ struct device *dev = &qm->pdev->dev; u16 xeq_depth; size_t size; void *xeqe; u32 xeqe_id; int ret; if (!s) return -EINVAL; ret = kstrtou32(s, 0, &xeqe_id); if (ret) return -EINVAL; if (!strcmp(name, "EQE")) { xeq_depth = qm->eq_depth; size = sizeof(struct qm_eqe); } else { xeq_depth = qm->aeq_depth; size = sizeof(struct qm_aeqe); } if (xeqe_id >= xeq_depth) { dev_err(dev, "Please input eqe or aeqe num (0-%d)", xeq_depth - 1); return -EINVAL; } down_read(&qm->qps_lock); if (qm->eqe && !strcmp(name, "EQE")) { xeqe = qm->eqe + xeqe_id; } else if (qm->aeqe && !strcmp(name, "AEQE")) { xeqe = qm->aeqe + xeqe_id; } else { ret = -EINVAL; goto err_unlock; } dump_show(qm, xeqe, size, name); err_unlock: up_read(&qm->qps_lock); return ret;} static int qm_dbg_help(struct hisi_qm *qm, char *s){ struct device *dev = &qm->pdev->dev; if (strsep(&s, " ")) { dev_err(dev, "Please do not input extra characters!\n"); return -EINVAL; } dev_info(dev, "available commands:\n"); dev_info(dev, "sqc <num>\n"); dev_info(dev, "cqc <num>\n"); dev_info(dev, "eqc\n"); dev_info(dev, "aeqc\n"); dev_info(dev, "sq <num> <e>\n"); dev_info(dev, "cq <num> <e>\n"); dev_info(dev, "eq <e>\n"); dev_info(dev, "aeq <e>\n"); return 0;} static const struct qm_cmd_dump_item qm_cmd_dump_table[] = { { .cmd = "sqc", .info_name = "SQC", .dump_fn = qm_sqc_dump, }, { .cmd = "cqc", .info_name = "CQC", .dump_fn = qm_cqc_dump, }, { .cmd = "eqc", .info_name = "EQC", .dump_fn = qm_eqc_aeqc_dump, }, { .cmd = "aeqc", .info_name = "AEQC", .dump_fn = qm_eqc_aeqc_dump, }, { .cmd = "sq", .info_name = "SQE", .dump_fn = qm_sq_dump, }, { .cmd = "cq", .info_name = "CQE", .dump_fn = qm_cq_dump, }, { .cmd = "eq", .info_name = "EQE", .dump_fn = qm_eq_aeq_dump, }, { .cmd = "aeq", .info_name = "AEQE", .dump_fn = qm_eq_aeq_dump, },}; static int qm_cmd_write_dump(struct hisi_qm *qm, const char *cmd_buf){ struct device *dev = &qm->pdev->dev; char *presult, *s, *s_tmp; int table_size, i, ret; s = kstrdup(cmd_buf, GFP_KERNEL); if (!s) return -ENOMEM; s_tmp = s; presult = strsep(&s, " "); if (!presult) { ret = -EINVAL; goto err_buffer_free; } if (!strcmp(presult, "help")) { ret = qm_dbg_help(qm, s); goto err_buffer_free; } table_size = ARRAY_SIZE(qm_cmd_dump_table); for (i = 0; i < table_size; i++) { if (!strcmp(presult, qm_cmd_dump_table[i].cmd)) { ret = qm_cmd_dump_table[i].dump_fn(qm, s, qm_cmd_dump_table[i].info_name); break; } }Lines 1–500 of 1272. Load more
// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2022 HiSilicon Limited. */ #include <linux/hisi_acc_qm.h> #include "qm_common.h" #define QM_DFX_BASE 0x0100000 #define QM_DFX_STATE1 0x0104000 #define QM_DFX_STATE2 0x01040C8 #define QM_DFX_COMMON 0x0000 #define QM_DFX_BASE_LEN 0x5A #define QM_DFX_STATE1_LEN 0x2E #define QM_DFX_STATE2_LEN 0x11 #define QM_DFX_COMMON_LEN 0xC3 #define QM_DFX_REGS_LEN 4UL #define QM_DBG_TMP_BUF_LEN 22 #define QM_XQC_ADDR_MASK GENMASK(31, 0) #define CURRENT_FUN_MASK GENMASK(5, 0) #define CURRENT_Q_MASK GENMASK(31, 16) #define QM_SQE_ADDR_MASK GENMASK(7, 0) #define QM_DFX_MB_CNT_VF 0x104010 #define QM_DFX_DB_CNT_VF 0x104020 #define QM_DFX_SQE_CNT_VF_SQN 0x104030 #define QM_DFX_CQE_CNT_VF_CQN 0x104040 #define QM_DFX_QN_SHIFT 16 #define QM_DFX_CNT_CLR_CE 0x100118 #define QM_DBG_WRITE_LEN 1024 #define QM_IN_IDLE_ST_REG 0x1040e4 #define QM_IN_IDLE_STATE 0x1 static const char * const qm_debug_file_name[] = { [CURRENT_QM] = "current_qm", [CURRENT_Q] = "current_q", [CLEAR_ENABLE] = "clear_enable", }; static const char * const qm_s[] = { "work", "stop", }; struct qm_dfx_item { const char *name; u32 offset; }; struct qm_cmd_dump_item { const char *cmd; const char *info_name; int (*dump_fn)(struct hisi_qm *qm, char *cmd, const char *info_name); }; static struct qm_dfx_item qm_dfx_files[] = { {"err_irq", offsetof(struct qm_dfx, err_irq_cnt)}, {"aeq_irq", offsetof(struct qm_dfx, aeq_irq_cnt)}, {"abnormal_irq", offsetof(struct qm_dfx, abnormal_irq_cnt)}, {"create_qp_err", offsetof(struct qm_dfx, create_qp_err_cnt)}, {"mb_err", offsetof(struct qm_dfx, mb_err_cnt)}, }; #define CNT_CYC_REGS_NUM 10 static const struct debugfs_reg32 qm_dfx_regs[] = { /* XXX_CNT are reading clear register */ {"QM_ECC_1BIT_CNT ", 0x104000}, {"QM_ECC_MBIT_CNT ", 0x104008}, {"QM_DFX_MB_CNT ", 0x104018}, {"QM_DFX_DB_CNT ", 0x104028}, {"QM_DFX_SQE_CNT ", 0x104038}, {"QM_DFX_CQE_CNT ", 0x104048}, {"QM_DFX_SEND_SQE_TO_ACC_CNT ", 0x104050}, {"QM_DFX_WB_SQE_FROM_ACC_CNT ", 0x104058}, {"QM_DFX_ACC_FINISH_CNT ", 0x104060}, {"QM_DFX_CQE_ERR_CNT ", 0x1040b4}, {"QM_DFX_FUNS_ACTIVE_ST ", 0x200}, {"QM_ECC_1BIT_INF ", 0x104004}, {"QM_ECC_MBIT_INF ", 0x10400c}, {"QM_DFX_ACC_RDY_VLD0 ", 0x1040a0}, {"QM_DFX_ACC_RDY_VLD1 ", 0x1040a4}, {"QM_DFX_AXI_RDY_VLD ", 0x1040a8}, {"QM_DFX_FF_ST0 ", 0x1040c8}, {"QM_DFX_FF_ST1 ", 0x1040cc}, {"QM_DFX_FF_ST2 ", 0x1040d0}, {"QM_DFX_FF_ST3 ", 0x1040d4}, {"QM_DFX_FF_ST4 ", 0x1040d8}, {"QM_DFX_FF_ST5 ", 0x1040dc}, {"QM_DFX_FF_ST6 ", 0x1040e0}, {"QM_IN_IDLE_ST ", 0x1040e4}, {"QM_CACHE_CTL ", 0x100050}, {"QM_TIMEOUT_CFG ", 0x100070}, {"QM_DB_TIMEOUT_CFG ", 0x100074}, {"QM_FLR_PENDING_TIME_CFG ", 0x100078}, {"QM_ARUSR_MCFG1 ", 0x100088}, {"QM_AWUSR_MCFG1 ", 0x100098}, {"QM_AXI_M_CFG_ENABLE ", 0x1000B0}, {"QM_RAS_CE_THRESHOLD ", 0x1000F8}, {"QM_AXI_TIMEOUT_CTRL ", 0x100120}, {"QM_AXI_TIMEOUT_STATUS ", 0x100124}, {"QM_CQE_AGGR_TIMEOUT_CTRL ", 0x100144}, {"ACC_RAS_MSI_INT_SEL ", 0x1040fc}, {"QM_CQE_OUT ", 0x104100}, {"QM_EQE_OUT ", 0x104104}, {"QM_AEQE_OUT ", 0x104108}, {"QM_DB_INFO0 ", 0x104180}, {"QM_DB_INFO1 ", 0x104184}, {"QM_AM_CTRL_GLOBAL ", 0x300000}, {"QM_AM_CURR_PORT_STS ", 0x300100}, {"QM_AM_CURR_TRANS_RETURN ", 0x300150}, {"QM_AM_CURR_RD_MAX_TXID ", 0x300154}, {"QM_AM_CURR_WR_MAX_TXID ", 0x300158}, {"QM_AM_ALARM_RRESP ", 0x300180}, {"QM_AM_ALARM_BRESP ", 0x300184}, }; static const struct debugfs_reg32 qm_vf_dfx_regs[] = { {"QM_DFX_FUNS_ACTIVE_ST ", 0x200}, }; /* define the QM's dfx regs region and region length */ static struct dfx_diff_registers qm_diff_regs[] = { { .reg_offset = QM_DFX_BASE, .reg_len = QM_DFX_BASE_LEN, }, { .reg_offset = QM_DFX_STATE1, .reg_len = QM_DFX_STATE1_LEN, }, { .reg_offset = QM_DFX_STATE2, .reg_len = QM_DFX_STATE2_LEN, }, { .reg_offset = QM_DFX_COMMON, .reg_len = QM_DFX_COMMON_LEN, }, }; static struct hisi_qm *file_to_qm(struct debugfs_file *file) { struct qm_debug *debug = file->debug; return container_of(debug, struct hisi_qm, debug); } static ssize_t qm_cmd_read(struct file *filp, char __user *buffer, size_t count, loff_t *pos) { char buf[QM_DBG_READ_LEN]; int len; len = scnprintf(buf, QM_DBG_READ_LEN, "%s\n", "Please echo help to cmd to get help information"); return simple_read_from_buffer(buffer, count, pos, buf, len); } static void dump_show(struct hisi_qm *qm, void *info, unsigned int info_size, const char *info_name) { struct device *dev = &qm->pdev->dev; u8 *info_curr = info; u32 i; #define BYTE_PER_DW 4 dev_info(dev, "%s DUMP\n", info_name); for (i = 0; i < info_size; i += BYTE_PER_DW, info_curr += BYTE_PER_DW) { pr_info("DW%u: %02X%02X %02X%02X\n", i / BYTE_PER_DW, *(info_curr + 3), *(info_curr + 2), *(info_curr + 1), *(info_curr)); } } static int qm_sqc_dump(struct hisi_qm *qm, char *s, const char *name) { struct device *dev = &qm->pdev->dev; struct qm_sqc sqc; u32 qp_id; int ret; if (!s) return -EINVAL; ret = kstrtou32(s, 0, &qp_id); if (ret || qp_id >= qm->qp_num) { dev_err(dev, "Please input qp num (0-%u)", qm->qp_num - 1); return -EINVAL; } ret = qm_set_and_get_xqc(qm, QM_MB_CMD_SQC, &sqc, qp_id, 1); if (!ret) { sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &sqc, sizeof(struct qm_sqc), name); return 0; } down_read(&qm->qps_lock); if (qm->sqc) { memcpy(&sqc, qm->sqc + qp_id, sizeof(struct qm_sqc)); sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &sqc, sizeof(struct qm_sqc), "SOFT SQC"); } up_read(&qm->qps_lock); return 0; } static int qm_cqc_dump(struct hisi_qm *qm, char *s, const char *name) { struct device *dev = &qm->pdev->dev; struct qm_cqc cqc; u32 qp_id; int ret; if (!s) return -EINVAL; ret = kstrtou32(s, 0, &qp_id); if (ret || qp_id >= qm->qp_num) { dev_err(dev, "Please input qp num (0-%u)", qm->qp_num - 1); return -EINVAL; } ret = qm_set_and_get_xqc(qm, QM_MB_CMD_CQC, &cqc, qp_id, 1); if (!ret) { cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &cqc, sizeof(struct qm_cqc), name); return 0; } down_read(&qm->qps_lock); if (qm->cqc) { memcpy(&cqc, qm->cqc + qp_id, sizeof(struct qm_cqc)); cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &cqc, sizeof(struct qm_cqc), "SOFT CQC"); } up_read(&qm->qps_lock); return 0; } static int qm_eqc_aeqc_dump(struct hisi_qm *qm, char *s, const char *name) { struct device *dev = &qm->pdev->dev; struct qm_aeqc aeqc; struct qm_eqc eqc; size_t size; void *xeqc; int ret; u8 cmd; if (strsep(&s, " ")) { dev_err(dev, "Please do not input extra characters!\n"); return -EINVAL; } if (!strcmp(name, "EQC")) { cmd = QM_MB_CMD_EQC; size = sizeof(struct qm_eqc); xeqc = &eqc; } else { cmd = QM_MB_CMD_AEQC; size = sizeof(struct qm_aeqc); xeqc = &aeqc; } ret = qm_set_and_get_xqc(qm, cmd, xeqc, 0, 1); if (ret) return ret; aeqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); aeqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); eqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); eqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, xeqc, size, name); return ret; } static int q_dump_param_parse(struct hisi_qm *qm, char *s, u32 *e_id, u32 *q_id, u16 q_depth) { struct device *dev = &qm->pdev->dev; unsigned int qp_num = qm->qp_num; char *presult; int ret; presult = strsep(&s, " "); if (!presult) { dev_err(dev, "Please input qp number!\n"); return -EINVAL; } ret = kstrtou32(presult, 0, q_id); if (ret || *q_id >= qp_num) { dev_err(dev, "Please input qp num (0-%u)", qp_num - 1); return -EINVAL; } presult = strsep(&s, " "); if (!presult) { dev_err(dev, "Please input sqe number!\n"); return -EINVAL; } ret = kstrtou32(presult, 0, e_id); if (ret || *e_id >= q_depth) { dev_err(dev, "Please input sqe num (0-%d)", q_depth - 1); return -EINVAL; } if (strsep(&s, " ")) { dev_err(dev, "Please do not input extra characters!\n"); return -EINVAL; } return 0; } static int qm_sq_dump(struct hisi_qm *qm, char *s, const char *name) { u16 sq_depth = qm->qp_array->sq_depth; struct hisi_qp *qp; u32 qp_id, sqe_id; void *sqe; int ret; ret = q_dump_param_parse(qm, s, &sqe_id, &qp_id, sq_depth); if (ret) return ret; sqe = kzalloc(qm->sqe_size, GFP_KERNEL); if (!sqe) return -ENOMEM; qp = &qm->qp_array[qp_id]; memcpy(sqe, qp->sqe + sqe_id * qm->sqe_size, qm->sqe_size); memset(sqe + qm->debug.sqe_mask_offset, QM_SQE_ADDR_MASK, qm->debug.sqe_mask_len); dump_show(qm, sqe, qm->sqe_size, name); kfree(sqe); return 0; } static int qm_cq_dump(struct hisi_qm *qm, char *s, const char *name) { struct qm_cqe *cqe_curr; struct hisi_qp *qp; u32 qp_id, cqe_id; int ret; ret = q_dump_param_parse(qm, s, &cqe_id, &qp_id, qm->qp_array->cq_depth); if (ret) return ret; qp = &qm->qp_array[qp_id]; cqe_curr = qp->cqe + cqe_id; dump_show(qm, cqe_curr, sizeof(struct qm_cqe), name); return 0; } static int qm_eq_aeq_dump(struct hisi_qm *qm, char *s, const char *name) { struct device *dev = &qm->pdev->dev; u16 xeq_depth; size_t size; void *xeqe; u32 xeqe_id; int ret; if (!s) return -EINVAL; ret = kstrtou32(s, 0, &xeqe_id); if (ret) return -EINVAL; if (!strcmp(name, "EQE")) { xeq_depth = qm->eq_depth; size = sizeof(struct qm_eqe); } else { xeq_depth = qm->aeq_depth; size = sizeof(struct qm_aeqe); } if (xeqe_id >= xeq_depth) { dev_err(dev, "Please input eqe or aeqe num (0-%d)", xeq_depth - 1); return -EINVAL; } down_read(&qm->qps_lock); if (qm->eqe && !strcmp(name, "EQE")) { xeqe = qm->eqe + xeqe_id; } else if (qm->aeqe && !strcmp(name, "AEQE")) { xeqe = qm->aeqe + xeqe_id; } else { ret = -EINVAL; goto err_unlock; } dump_show(qm, xeqe, size, name); err_unlock: up_read(&qm->qps_lock); return ret; } static int qm_dbg_help(struct hisi_qm *qm, char *s) { struct device *dev = &qm->pdev->dev; if (strsep(&s, " ")) { dev_err(dev, "Please do not input extra characters!\n"); return -EINVAL; } dev_info(dev, "available commands:\n"); dev_info(dev, "sqc <num>\n"); dev_info(dev, "cqc <num>\n"); dev_info(dev, "eqc\n"); dev_info(dev, "aeqc\n"); dev_info(dev, "sq <num> <e>\n"); dev_info(dev, "cq <num> <e>\n"); dev_info(dev, "eq <e>\n"); dev_info(dev, "aeq <e>\n"); return 0; } static const struct qm_cmd_dump_item qm_cmd_dump_table[] = { { .cmd = "sqc", .info_name = "SQC", .dump_fn = qm_sqc_dump, }, { .cmd = "cqc", .info_name = "CQC", .dump_fn = qm_cqc_dump, }, { .cmd = "eqc", .info_name = "EQC", .dump_fn = qm_eqc_aeqc_dump, }, { .cmd = "aeqc", .info_name = "AEQC", .dump_fn = qm_eqc_aeqc_dump, }, { .cmd = "sq", .info_name = "SQE", .dump_fn = qm_sq_dump, }, { .cmd = "cq", .info_name = "CQE", .dump_fn = qm_cq_dump, }, { .cmd = "eq", .info_name = "EQE", .dump_fn = qm_eq_aeq_dump, }, { .cmd = "aeq", .info_name = "AEQE", .dump_fn = qm_eq_aeq_dump, }, }; static int qm_cmd_write_dump(struct hisi_qm *qm, const char *cmd_buf) { struct device *dev = &qm->pdev->dev; char *presult, *s, *s_tmp; int table_size, i, ret; s = kstrdup(cmd_buf, GFP_KERNEL); if (!s) return -ENOMEM; s_tmp = s; presult = strsep(&s, " "); if (!presult) { ret = -EINVAL; goto err_buffer_free; } if (!strcmp(presult, "help")) { ret = qm_dbg_help(qm, s); goto err_buffer_free; } table_size = ARRAY_SIZE(qm_cmd_dump_table); for (i = 0; i < table_size; i++) { if (!strcmp(presult, qm_cmd_dump_table[i].cmd)) { ret = qm_cmd_dump_table[i].dump_fn(qm, s, qm_cmd_dump_table[i].info_name); break; } }