
From: Weili Qian <qianweili@huawei.com> driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ICESZH CVE: NA ---------------------------------------------------------------------- When hardware is abnormal, the values obtained from the hardware may be incorrect. Add checks to prevent unexpected errors when using these values. And remove the redundant vfs_num clearing. Fixes: 3e1d2c52b204 ("crypto: hisilicon - check _PS0 and _PR0 method") Signed-off-by: Weili Qian <qianweili@huawei.com> Signed-off-by: JiangShui Yang <yangjiangshui@h-partners.com> --- drivers/crypto/hisilicon/debugfs.c | 1 + drivers/crypto/hisilicon/qm.c | 47 +++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 45e130b901eb..17eb236e9ee4 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -888,6 +888,7 @@ static int qm_diff_regs_init(struct hisi_qm *qm, dfx_regs_uninit(qm, qm->debug.qm_diff_regs, ARRAY_SIZE(qm_diff_regs)); ret = PTR_ERR(qm->debug.acc_diff_regs); qm->debug.acc_diff_regs = NULL; + qm->debug.qm_diff_regs = NULL; return ret; } diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 06d8e7aa048b..3ba5de946d53 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -80,6 +80,8 @@ #define QM_EQ_OVERFLOW 1 #define QM_CQE_ERROR 2 +#define QM_XQC_MIN_DEPTH 1024 + #define QM_XQ_DEPTH_SHIFT 16 #define QM_XQ_DEPTH_MASK GENMASK(15, 0) @@ -3091,6 +3093,7 @@ static inline bool is_iommu_used(struct device *dev) static void hisi_qm_pre_init(struct hisi_qm *qm) { struct pci_dev *pdev = qm->pdev; + struct acpi_device *adev; if (qm->ver == QM_HW_V1) qm->ops = &qm_hw_ops_v1; @@ -3107,9 +3110,16 @@ static void hisi_qm_pre_init(struct hisi_qm *qm) init_rwsem(&qm->qps_lock); qm->qp_in_used = 0; qm->use_iommu = is_iommu_used(&pdev->dev); + /* + * If the firmware does not support power manageable, + * clear the flag to avoid entering the suspend and resume process later. + */ if (test_bit(QM_SUPPORT_RPM, &qm->caps)) { - if (!acpi_device_power_manageable(ACPI_COMPANION(&pdev->dev))) - dev_info(&pdev->dev, "_PS0 and _PR0 are not defined"); + adev = ACPI_COMPANION(&pdev->dev); + if (!adev || !acpi_device_power_manageable(adev)) { + dev_info(&pdev->dev, "_PS0 and _PR0 are not defined!\n"); + clear_bit(QM_SUPPORT_RPM, &qm->caps); + } } } @@ -3814,7 +3824,6 @@ static int qm_clear_vft_config(struct hisi_qm *qm) if (ret) return ret; } - qm->vfs_num = 0; return 0; } @@ -4749,6 +4758,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm) qm_restart_prepare(qm); qm_dev_err_init(qm); qm_disable_axi_error(qm); + qm_restart_done(qm); if (qm->err_ini->open_axi_master_ooo) qm->err_ini->open_axi_master_ooo(qm); @@ -4773,8 +4783,6 @@ static int qm_controller_reset_done(struct hisi_qm *qm) pci_err(pdev, "failed to start by vfs in soft reset!\n"); qm_enable_axi_error(qm); qm_cmd_init(qm); - qm_restart_done(qm); - qm_reset_bit_clear(qm); return 0; @@ -5410,7 +5418,15 @@ static int qm_init_eq_work(struct hisi_qm *qm) if (!qm->poll_data) return ret; + /* Check the minimum value to avoid array out of boundary errors. */ qm_get_xqc_depth(qm, &qm->eq_depth, &qm->aeq_depth, QM_XEQ_DEPTH_CAP); + if (qm->eq_depth < QM_XQC_MIN_DEPTH || qm->aeq_depth < QM_XQC_MIN_DEPTH) { + dev_err(&qm->pdev->dev, "invalid, eq depth %u, aeq depth %u, the min value %u!\n", + qm->eq_depth, qm->aeq_depth, QM_XQC_MIN_DEPTH); + kfree(qm->poll_data); + return -EINVAL; + } + eq_depth = qm->eq_depth >> 1; for (i = 0; i < qm->qp_num; i++) { qm->poll_data[i].qp_finish_id = kcalloc(eq_depth, sizeof(u16), GFP_KERNEL); @@ -5595,9 +5611,11 @@ static int qm_get_hw_caps(struct hisi_qm *qm) if (val) set_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps); - if (qm->ver >= QM_HW_V3) { - val = readl(qm->io_base + QM_FUNC_CAPS_REG); - qm->cap_ver = val & QM_CAPBILITY_VERSION; + val = readl(qm->io_base + QM_FUNC_CAPS_REG); + qm->cap_ver = val & QM_CAPBILITY_VERSION; + if (qm->cap_ver == QM_CAPBILITY_VERSION) { + dev_err(&qm->pdev->dev, "Device is abnormal, return directly!\n"); + return -EINVAL; } /* Get PF/VF common capbility */ @@ -5787,17 +5805,24 @@ static int hisi_qp_alloc_memory(struct hisi_qm *qm) if (!qm->qp_array) return -ENOMEM; + /* Check the minimum value to avoid division by zero later. */ qm_get_xqc_depth(qm, &sq_depth, &cq_depth, QM_QP_DEPTH_CAP); + if (sq_depth < QM_XQC_MIN_DEPTH || cq_depth < QM_XQC_MIN_DEPTH) { + dev_err(dev, "invalid, sq depth %u, cq depth %u, the min value %u!\n", + sq_depth, cq_depth, QM_XQC_MIN_DEPTH); + kfree(qm->qp_array); + return -EINVAL; + } /* one more page for device or qp statuses */ qp_dma_size = qm->sqe_size * sq_depth + sizeof(struct qm_cqe) * cq_depth; qp_dma_size = PAGE_ALIGN(qp_dma_size) + PAGE_SIZE; for (i = 0; i < qm->qp_num; i++) { ret = hisi_qp_memory_init(qm, qp_dma_size, i, sq_depth, cq_depth); - if (ret) + if (ret) { + dev_err(dev, "failed to allocate qp dma buf size=%zx)\n", qp_dma_size); goto err_init_qp_mem; - - dev_dbg(dev, "allocate qp dma buf size=%zx)\n", qp_dma_size); + } } return 0; -- 2.33.0