driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8LFYK CVE: NA
----------------------------------------------------------------------
When the device is re-enabled, data that has not been cleared may exist on the device. Therefore, reset the device to the initial state before enabling the device. If an abnormal interrupt event is reported when the device is enabled, the device will not be reset.
Signed-off-by: Weili Qian qianweili@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- drivers/crypto/hisilicon/hpre/hpre_main.c | 27 +++++--- drivers/crypto/hisilicon/qm.c | 77 ++++++++++++++++++++--- drivers/crypto/hisilicon/sec2/sec_main.c | 22 +++++-- drivers/crypto/hisilicon/zip/zip_main.c | 19 +++++- 4 files changed, 120 insertions(+), 25 deletions(-)
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 615a90829495..7829db84d29b 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -1350,6 +1350,17 @@ static const struct hisi_qm_err_ini hpre_err_ini = { .err_info_init = hpre_err_info_init, };
+static void hpre_probe_uninit(struct hisi_qm *qm) +{ + if (qm->fun_type == QM_HW_VF) + return; + + hpre_cnt_regs_clear(qm); + qm->debug.curr_qm_qp_num = 0; + hpre_show_last_regs_uninit(qm); + hpre_close_sva_prefetch(qm); +} + static int hpre_pf_probe_init(struct hpre *hpre) { struct hisi_qm *qm = &hpre->qm; @@ -1398,6 +1409,7 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM;
qm = &hpre->qm; + set_bit(QM_DRIVER_DOWN, &qm->misc_ctl); ret = hpre_qm_init(qm, pdev); if (ret) { pci_err(pdev, "Failed to init HPRE QM (%d)!\n", ret); @@ -1414,6 +1426,9 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto err_with_err_init;
+ /* Device is enabled, clear the flag. */ + clear_bit(QM_DRIVER_DOWN, &qm->misc_ctl); + ret = hpre_debugfs_init(qm); if (ret) dev_warn(&pdev->dev, "init debugfs fail!\n"); @@ -1446,12 +1461,12 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_qm_del_list: hisi_qm_del_list(qm, &hpre_devices); + hisi_qm_wait_task_finish(qm, &hpre_devices); hpre_debugfs_exit(qm); hisi_qm_stop(qm, QM_NORMAL);
err_with_err_init: - hpre_show_last_regs_uninit(qm); - + hpre_probe_uninit(qm); err_with_qm_init: hisi_qm_uninit(qm);
@@ -1471,13 +1486,7 @@ static void hpre_remove(struct pci_dev *pdev)
hpre_debugfs_exit(qm); hisi_qm_stop(qm, QM_NORMAL); - - if (qm->fun_type == QM_HW_PF) { - hpre_cnt_regs_clear(qm); - qm->debug.curr_qm_qp_num = 0; - hpre_show_last_regs_uninit(qm); - } - + hpre_probe_uninit(qm); hisi_qm_uninit(qm); }
diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 0d6cf559d275..e7c73eccb259 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -445,6 +445,7 @@ static struct qm_typical_qos_table shaper_cbs_s[] = { };
static void qm_irqs_unregister(struct hisi_qm *qm); +static int qm_reset_device(struct hisi_qm *qm);
static u32 qm_get_hw_error_status(struct hisi_qm *qm) { @@ -3004,6 +3005,44 @@ static void hisi_qm_memory_uninit(struct hisi_qm *qm) kfree(qm->factor); }
+static int qm_clear_device(struct hisi_qm *qm) +{ + acpi_handle handle = ACPI_HANDLE(&qm->pdev->dev); + u32 val; + int ret; + + if (qm->fun_type == QM_HW_VF) + return 0; + + /* Device does not support reset, return */ + if (!qm->err_ini->err_info_init) + return 0; + + qm->err_ini->err_info_init(qm); + + if (!handle) + return 0; + + /* No reset method, return */ + if (!acpi_has_method(handle, qm->err_info.acpi_rst)) + return 0; + + /* OOO register set and check */ + writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, qm->io_base + ACC_MASTER_GLOBAL_CTRL); + + ret = readl_relaxed_poll_timeout(qm->io_base + ACC_MASTER_TRANS_RETURN, + val, + (val == ACC_MASTER_TRANS_RETURN_RW), + POLL_PERIOD, POLL_TIMEOUT); + if (ret) { + pci_warn(qm->pdev, "Device is busy, not clear device.\n"); + writel(0x0, qm->io_base + ACC_MASTER_GLOBAL_CTRL); + return ret; + } + + return qm_reset_device(qm); +} + /** * hisi_qm_uninit() - Uninitialize qm. * @qm: The qm needed uninit. @@ -4283,7 +4322,7 @@ static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm) } }
-static int qm_soft_reset(struct hisi_qm *qm) +static int qm_soft_reset_prepare(struct hisi_qm *qm) { struct pci_dev *pdev = qm->pdev; int ret; @@ -4328,10 +4367,15 @@ static int qm_soft_reset(struct hisi_qm *qm) qm->err_ini->close_sva_prefetch(qm);
ret = qm_set_pf_mse(qm, false); - if (ret) { + if (ret) pci_err(pdev, "Fails to disable pf MSE bit.\n"); - return ret; - } + + return ret; +} + +static int qm_reset_device(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev;
/* The reset related sub-control registers are not in PCI BAR */ if (ACPI_HANDLE(&pdev->dev)) { @@ -4350,12 +4394,23 @@ static int qm_soft_reset(struct hisi_qm *qm) pci_err(pdev, "Reset step %llu failed!\n", value); return -EIO; } - } else { - pci_err(pdev, "No reset method!\n"); - return -EINVAL; + + return 0; }
- return 0; + pci_err(pdev, "No reset method!\n"); + return -EINVAL; +} + +static int qm_soft_reset(struct hisi_qm *qm) +{ + int ret; + + ret = qm_soft_reset_prepare(qm); + if (ret) + return ret; + + return qm_reset_device(qm); }
static int qm_vf_reset_done(struct hisi_qm *qm) @@ -5442,8 +5497,14 @@ static int hisi_qm_pci_init(struct hisi_qm *qm) goto err_get_pci_res; }
+ ret = qm_clear_device(qm); + if (ret) + goto err_free_vectors; + return 0;
+err_free_vectors: + pci_free_irq_vectors(pdev); err_get_pci_res: qm_put_pci_res(qm); err_disable_pcidev: diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index f20e71dfbce4..024c574f4c1c 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -1199,6 +1199,16 @@ static int sec_probe_init(struct sec_dev *sec) return 0; }
+static void sec_probe_uninit(struct hisi_qm *qm) +{ + if (qm->fun_type == QM_HW_VF) + return; + + sec_debug_regs_clear(qm); + sec_show_last_regs_uninit(qm); + sec_close_sva_prefetch(qm); +} + static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct sec_dev *sec; @@ -1210,6 +1220,7 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM;
qm = &sec->qm; + set_bit(QM_DRIVER_DOWN, &qm->misc_ctl); ret = sec_qm_init(qm, pdev); if (ret) { pci_err(pdev, "Failed to init SEC QM (%d)!\n", ret); @@ -1230,6 +1241,9 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_probe_uninit; }
+ /* Device is enabled, clear the flag. */ + clear_bit(QM_DRIVER_DOWN, &qm->misc_ctl); + ret = sec_debugfs_init(qm); if (ret) pci_warn(pdev, "Failed to init debugfs!\n"); @@ -1263,10 +1277,11 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) hisi_qm_alg_unregister(qm, &sec_devices, ctx_q_num); err_qm_del_list: hisi_qm_del_list(qm, &sec_devices); + hisi_qm_wait_task_finish(qm, &sec_devices); sec_debugfs_exit(qm); hisi_qm_stop(qm, QM_NORMAL); err_probe_uninit: - sec_show_last_regs_uninit(qm); + sec_probe_uninit(qm); err_qm_uninit: sec_qm_uninit(qm); return ret; @@ -1287,10 +1302,7 @@ static void sec_remove(struct pci_dev *pdev) sec_debugfs_exit(qm);
(void)hisi_qm_stop(qm, QM_NORMAL); - - if (qm->fun_type == QM_HW_PF) - sec_debug_regs_clear(qm); - sec_show_last_regs_uninit(qm); + sec_probe_uninit(qm);
sec_qm_uninit(qm); } diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index aeab08fbbb04..5e1fe52e9074 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -1294,6 +1294,15 @@ static int hisi_zip_probe_init(struct hisi_zip *hisi_zip) return 0; }
+static void hisi_zip_probe_uninit(struct hisi_qm *qm) +{ + if (qm->fun_type == QM_HW_VF) + return; + + hisi_zip_show_last_regs_uninit(qm); + hisi_zip_close_sva_prefetch(qm); +} + static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct hisi_zip *hisi_zip; @@ -1305,7 +1314,7 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENOMEM;
qm = &hisi_zip->qm; - + set_bit(QM_DRIVER_DOWN, &qm->misc_ctl); ret = hisi_zip_qm_init(qm, pdev); if (ret) { pci_err(pdev, "Failed to init ZIP QM (%d)!\n", ret); @@ -1322,6 +1331,9 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto err_dev_err_uninit;
+ /* Device is enabled, clear the flag. */ + clear_bit(QM_DRIVER_DOWN, &qm->misc_ctl); + ret = hisi_zip_debugfs_init(qm); if (ret) pci_err(pdev, "failed to init debugfs (%d)!\n", ret); @@ -1355,12 +1367,13 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) hisi_qm_alg_unregister(qm, &zip_devices, HZIP_CTX_Q_NUM_DEF);
err_qm_del_list: + hisi_qm_wait_task_finish(qm, &zip_devices); hisi_qm_del_list(qm, &zip_devices); hisi_zip_debugfs_exit(qm); hisi_qm_stop(qm, QM_NORMAL);
err_dev_err_uninit: - hisi_zip_show_last_regs_uninit(qm); + hisi_zip_probe_uninit(qm);
err_qm_uninit: hisi_zip_qm_uninit(qm); @@ -1382,7 +1395,7 @@ static void hisi_zip_remove(struct pci_dev *pdev)
hisi_zip_debugfs_exit(qm); hisi_qm_stop(qm, QM_NORMAL); - hisi_zip_show_last_regs_uninit(qm); + hisi_zip_probe_uninit(qm); hisi_zip_qm_uninit(qm); }