From: Zhushuai Yin <yinzhushuai@huawei.com> driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IDC64W CVE: NA ---------------------------------------------------------------------- To avoid accessing memory of a suspended device, and since the counter interface used by PM involves sleep operations, the counter interface cannot be placed in the interrupt top half. Therefore, the interface for acquiring the interrupt status in the RAS reset flow that resides in the interrupt context needs to be moved to the bottom half for processing. Fixes:607c191b371d ("crypto: hisilicon - support runtime PM for accelerator device") Signed-off-by: Zhushuai Yin <yinzhushuai@huawei.com> Signed-off-by: JiangShui Yang <yangjiangshui@h-partners.com> --- drivers/crypto/hisilicon/qm.c | 45 +++++++++++++++++++---------------- include/linux/hisi_acc_qm.h | 1 - 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 3c8b037d0d3c..ae7132a84e4a 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -3082,9 +3082,9 @@ void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list) msleep(WAIT_PERIOD); } - while (test_bit(QM_RST_SCHED, &qm->misc_ctl) || - test_bit(QM_RESETTING, &qm->misc_ctl)) - msleep(WAIT_PERIOD); + /* Cancel possible RAS reset process during the uninstallation procedure. */ + if (qm->fun_type == QM_HW_PF) + cancel_work_sync(&qm->rst_work); if (test_bit(QM_SUPPORT_MB_COMMAND, &qm->caps)) flush_work(&qm->cmd_process); @@ -4637,8 +4637,6 @@ static int qm_controller_reset_prepare(struct hisi_qm *qm) if (ret) pci_err(pdev, "failed to stop by vfs in soft reset!\n"); - clear_bit(QM_RST_SCHED, &qm->misc_ctl); - return 0; } @@ -4947,12 +4945,8 @@ static int qm_controller_reset(struct hisi_qm *qm) pci_info(pdev, "Controller resetting...\n"); ret = qm_controller_reset_prepare(qm); - if (ret) { - hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET); - hisi_qm_set_hw_reset(qm, QM_RESET_STOP_RX_OFFSET); - clear_bit(QM_RST_SCHED, &qm->misc_ctl); - return ret; - } + if (ret) + goto err_prepare; hisi_qm_show_last_dfx_regs(qm); if (qm->err_ini->show_last_dfx_regs) @@ -4970,6 +4964,13 @@ static int qm_controller_reset(struct hisi_qm *qm) return 0; +err_prepare: + pci_info(pdev, "Controller reset_prepare failed\n"); + writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, + qm->io_base + ACC_MASTER_GLOBAL_CTRL); + hisi_qm_set_hw_reset(qm, QM_RESET_STOP_TX_OFFSET); + hisi_qm_set_hw_reset(qm, QM_RESET_STOP_RX_OFFSET); + err_reset: pci_err(pdev, "Controller reset failed (%d)\n", ret); qm_reset_bit_clear(qm); @@ -5137,17 +5138,13 @@ static irqreturn_t qm_rsvd_irq(int irq, void *data) static irqreturn_t qm_abnormal_irq(int irq, void *data) { struct hisi_qm *qm = data; - enum acc_err_result ret; atomic64_inc(&qm->debug.dfx.abnormal_irq_cnt); - ret = qm_process_dev_error(qm); - if (ret == ACC_ERR_NEED_RESET) { - if (!test_bit(QM_DRIVER_DOWN, &qm->misc_ctl) && - !test_and_set_bit(QM_RST_SCHED, &qm->misc_ctl)) - schedule_work(&qm->rst_work); - else if (test_bit(QM_DRIVER_DOWN, &qm->misc_ctl)) - pci_warn(qm->pdev, "Driver is down, need reload driver!\n"); - } + + if (!test_bit(QM_DRIVER_DOWN, &qm->misc_ctl)) + schedule_work(&qm->rst_work); + else + pci_warn(qm->pdev, "Driver is down, need to reload driver!\n"); return IRQ_HANDLED; } @@ -5176,7 +5173,13 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work) ret = qm_pm_get_sync(qm); if (ret) { - clear_bit(QM_RST_SCHED, &qm->misc_ctl); + dev_err(&qm->pdev->dev, "failed to get runtime PM for controller\n"); + return; + } + + ret = qm_process_dev_error(qm); + if (ret != ACC_ERR_NEED_RESET) { + qm_pm_put_sync(qm); return; } diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index d0141e045ccc..29023539f30b 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -150,7 +150,6 @@ enum qm_vf_state { enum qm_misc_ctl_bits { QM_DRIVER_DOWN = 0x0, - QM_RST_SCHED, QM_RESETTING, QM_MODULE_PARAM, QM_DEVICE_DOWN, -- 2.43.0