driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I7C6LD CVE: NA
----------------------------------------------------------------------
If an error that requires a device reset occurs, disable the error reporting before device reset is complete, enable the error reporting function after the reset is complete to prevent the same error from being reported repeatedly.
Fixes: eaebf4c3b103 ("crypto: hisilicon - Unify hardware error init/uninit into QM") Signed-off-by: Weili Qian qianweili@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- drivers/crypto/hisilicon/hpre/hpre_main.c | 25 ++++++-- drivers/crypto/hisilicon/qm.c | 76 ++++++++++++++++------- drivers/crypto/hisilicon/sec2/sec_main.c | 24 +++++-- drivers/crypto/hisilicon/zip/zip_main.c | 24 +++++-- include/linux/hisi_acc_qm.h | 4 ++ 5 files changed, 119 insertions(+), 34 deletions(-)
diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 82627fe2488d..a517d079351c 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -1265,11 +1265,26 @@ static u32 hpre_get_hw_err_status(struct hisi_qm *qm)
static void hpre_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) { - u32 nfe; - writel(err_sts, qm->io_base + HPRE_HAC_SOURCE_INT); - nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); - writel(nfe, qm->io_base + HPRE_RAS_NFE_ENB); +} + +static void hpre_disable_error_report(struct hisi_qm *qm, u32 err_type) +{ + u32 nfe_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); + writel(nfe_mask & (~err_type), qm->io_base + HPRE_RAS_NFE_ENB); +} + +static void hpre_enable_error_report(struct hisi_qm *qm) +{ + u32 nfe_mask, ce_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); + ce_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CE_MASK_CAP, qm->cap_ver); + + writel(nfe_mask, qm->io_base + HPRE_RAS_NFE_ENB); + writel(ce_mask, qm->io_base + HPRE_RAS_CE_ENB); }
static void hpre_open_axi_master_ooo(struct hisi_qm *qm) @@ -1309,6 +1324,8 @@ static const struct hisi_qm_err_ini hpre_err_ini = { .hw_err_disable = hpre_hw_error_disable, .get_dev_hw_err_status = hpre_get_hw_err_status, .clear_dev_hw_err_status = hpre_clear_hw_err_status, + .disable_error_report = hpre_disable_error_report, + .enable_error_report = hpre_enable_error_report, .log_dev_hw_err = hpre_log_hw_error, .open_axi_master_ooo = hpre_open_axi_master_ooo, .open_sva_prefetch = hpre_open_sva_prefetch, diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index a1e30adbe009..cb43cff04d81 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -375,7 +375,7 @@ struct hisi_qm_hw_ops { int (*debug_init)(struct hisi_qm *qm); void (*hw_error_init)(struct hisi_qm *qm); void (*hw_error_uninit)(struct hisi_qm *qm); - enum acc_err_result (*hw_error_handle)(struct hisi_qm *qm); + enum acc_err_result (*hw_error_handle)(struct hisi_qm *qm, bool need_reset); int (*set_msi)(struct hisi_qm *qm, bool set); };
@@ -1569,24 +1569,35 @@ static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) } }
-static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm) +static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm, bool need_reset) { u32 error_status, tmp;
/* read err sts */ tmp = readl(qm->io_base + QM_ABNORMAL_INT_STATUS); - error_status = qm->error_mask & tmp; - + error_status = tmp & (~qm->err_info.qm_err_type); + qm->err_info.qm_err_type |= tmp; if (error_status) { if (error_status & QM_ECC_MBIT) qm->err_status.is_qm_ecc_mbit = true;
qm_log_hw_error(qm, error_status); - if (error_status & qm->err_info.qm_reset_mask) + /* If the device is ready to reset, only print new error type. */ + if (!need_reset) + return ACC_ERR_RECOVERED; + + if (error_status & qm->err_info.qm_reset_mask) { + /* Disable the same error reporting until the error is recovered. */ + writel(qm->err_info.nfe & (~qm->err_info.qm_err_type), + qm->io_base + QM_RAS_NFE_ENABLE); return ACC_ERR_NEED_RESET; + }
- writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE); + /* Clear error source if not need reset. */ + writel(qm->err_info.qm_err_type, qm->io_base + QM_ABNORMAL_INT_SOURCE); + /* Avoid bios disable error type in v2 version, re-enable. */ writel(qm->err_info.nfe, qm->io_base + QM_RAS_NFE_ENABLE); + writel(qm->err_info.ce, qm->io_base + QM_RAS_CE_ENABLE); }
return ACC_ERR_RECOVERED; @@ -3446,14 +3457,14 @@ static void qm_hw_error_uninit(struct hisi_qm *qm) qm->ops->hw_error_uninit(qm); }
-static enum acc_err_result qm_hw_error_handle(struct hisi_qm *qm) +static enum acc_err_result qm_hw_error_handle(struct hisi_qm *qm, bool need_reset) { if (!qm->ops->hw_error_handle) { dev_err(&qm->pdev->dev, "QM doesn't support hw error report!\n"); return ACC_ERR_NONE; }
- return qm->ops->hw_error_handle(qm); + return qm->ops->hw_error_handle(qm, need_reset); }
/** @@ -4077,17 +4088,19 @@ int hisi_qm_sriov_configure(struct pci_dev *pdev, int num_vfs) } EXPORT_SYMBOL_GPL(hisi_qm_sriov_configure);
-static enum acc_err_result qm_dev_err_handle(struct hisi_qm *qm) +static enum acc_err_result qm_dev_err_handle(struct hisi_qm *qm, bool need_reset) { - u32 err_sts; + u32 err_sts, tmp;
if (!qm->err_ini->get_dev_hw_err_status) { dev_err(&qm->pdev->dev, "Device doesn't support get hw error status!\n"); return ACC_ERR_NONE; }
- /* get device hardware error status */ - err_sts = qm->err_ini->get_dev_hw_err_status(qm); + /* Get device hardware new error status */ + tmp = qm->err_ini->get_dev_hw_err_status(qm); + err_sts = tmp & (~qm->err_info.dev_err_type); + qm->err_info.dev_err_type |= tmp; if (err_sts) { if (err_sts & qm->err_info.ecc_2bits_mask) qm->err_status.is_dev_ecc_mbit = true; @@ -4095,11 +4108,21 @@ static enum acc_err_result qm_dev_err_handle(struct hisi_qm *qm) if (qm->err_ini->log_dev_hw_err) qm->err_ini->log_dev_hw_err(qm, err_sts);
- if (err_sts & qm->err_info.dev_reset_mask) + /* If the device is ready to reset, only print new error type. */ + if (!need_reset) + return ACC_ERR_RECOVERED; + + if (err_sts & qm->err_info.dev_reset_mask) { + /* Disable the same error reporting until the error is recovered. */ + qm->err_ini->disable_error_report(qm, qm->err_info.dev_err_type); return ACC_ERR_NEED_RESET; + }
- if (qm->err_ini->clear_dev_hw_err_status) - qm->err_ini->clear_dev_hw_err_status(qm, err_sts); + /* Clear error source if not need reset. */ + if (qm->err_ini->clear_dev_hw_err_status) { + qm->err_ini->clear_dev_hw_err_status(qm, qm->err_info.dev_err_type); + qm->err_ini->enable_error_report(qm); + } }
return ACC_ERR_RECOVERED; @@ -4108,16 +4131,25 @@ static enum acc_err_result qm_dev_err_handle(struct hisi_qm *qm) static enum acc_err_result qm_process_dev_error(struct hisi_qm *qm) { enum acc_err_result qm_ret, dev_ret; + bool need_reset = true; + + if (!test_bit(QM_RST_SCHED, &qm->misc_ctl)) { + qm->err_info.qm_err_type = 0; + qm->err_info.dev_err_type = 0; + } else { + need_reset = false; + }
/* log qm error */ - qm_ret = qm_hw_error_handle(qm); + qm_ret = qm_hw_error_handle(qm, need_reset);
/* log device error */ - dev_ret = qm_dev_err_handle(qm); + dev_ret = qm_dev_err_handle(qm, need_reset); + if (need_reset && (qm_ret == ACC_ERR_NEED_RESET || + dev_ret == ACC_ERR_NEED_RESET)) + return ACC_ERR_NEED_RESET;
- return (qm_ret == ACC_ERR_NEED_RESET || - dev_ret == ACC_ERR_NEED_RESET) ? - ACC_ERR_NEED_RESET : ACC_ERR_RECOVERED; + return ACC_ERR_RECOVERED; }
/** @@ -4317,8 +4349,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; }
@@ -4557,6 +4587,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm) return ret; } } + clear_bit(QM_RST_SCHED, &qm->misc_ctl);
ret = qm_dev_hw_init(qm); if (ret) { @@ -4630,6 +4661,7 @@ static int qm_controller_reset(struct hisi_qm *qm)
err_reset: pci_err(pdev, "Controller reset failed (%d)\n", ret); + clear_bit(QM_RST_SCHED, &qm->misc_ctl); qm_reset_bit_clear(qm);
/* if resetting fails, isolate the device */ diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 784416c0c559..b2eab04f989c 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -1012,11 +1012,25 @@ static u32 sec_get_hw_err_status(struct hisi_qm *qm)
static void sec_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) { - u32 nfe; - writel(err_sts, qm->io_base + SEC_CORE_INT_SOURCE); - nfe = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); - writel(nfe, qm->io_base + SEC_RAS_NFE_REG); +} + +static void sec_disable_error_report(struct hisi_qm *qm, u32 err_type) +{ + u32 nfe_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); + writel(nfe_mask & (~err_type), qm->io_base + SEC_RAS_NFE_REG); +} + +static void sec_enable_error_report(struct hisi_qm *qm) +{ + u32 nfe_mask, ce_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); + ce_mask = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_CE_MASK_CAP, qm->cap_ver); + writel(nfe_mask, qm->io_base + SEC_RAS_NFE_REG); + writel(ce_mask, qm->io_base + SEC_RAS_CE_REG); }
static void sec_open_axi_master_ooo(struct hisi_qm *qm) @@ -1054,6 +1068,8 @@ static const struct hisi_qm_err_ini sec_err_ini = { .hw_err_disable = sec_hw_error_disable, .get_dev_hw_err_status = sec_get_hw_err_status, .clear_dev_hw_err_status = sec_clear_hw_err_status, + .disable_error_report = sec_disable_error_report, + .enable_error_report = sec_enable_error_report, .log_dev_hw_err = sec_log_hw_error, .open_axi_master_ooo = sec_open_axi_master_ooo, .open_sva_prefetch = sec_open_sva_prefetch, diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index 1099c16f5555..6675c8198481 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -1008,11 +1008,25 @@ static u32 hisi_zip_get_hw_err_status(struct hisi_qm *qm)
static void hisi_zip_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) { - u32 nfe; - writel(err_sts, qm->io_base + HZIP_CORE_INT_SOURCE); - nfe = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); - writel(nfe, qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); +} + +static void hisi_zip_disable_error_report(struct hisi_qm *qm, u32 err_type) +{ + u32 nfe_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); + writel(nfe_mask & (~err_type), qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); +} + +static void hisi_zip_enable_error_report(struct hisi_qm *qm) +{ + u32 nfe_mask, ce_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); + ce_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CE_MASK_CAP, qm->cap_ver); + writel(nfe_mask, qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); + writel(ce_mask, qm->io_base + HZIP_CORE_INT_RAS_CE_ENB); }
static void hisi_zip_open_axi_master_ooo(struct hisi_qm *qm) @@ -1069,6 +1083,8 @@ static const struct hisi_qm_err_ini hisi_zip_err_ini = { .hw_err_disable = hisi_zip_hw_error_disable, .get_dev_hw_err_status = hisi_zip_get_hw_err_status, .clear_dev_hw_err_status = hisi_zip_clear_hw_err_status, + .disable_error_report = hisi_zip_disable_error_report, + .enable_error_report = hisi_zip_enable_error_report, .log_dev_hw_err = hisi_zip_log_hw_error, .open_axi_master_ooo = hisi_zip_open_axi_master_ooo, .close_axi_master_ooo = hisi_zip_close_axi_master_ooo, diff --git a/include/linux/hisi_acc_qm.h b/include/linux/hisi_acc_qm.h index f349144f2bd4..83d013f1bf39 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -252,6 +252,8 @@ struct hisi_qm_err_info { u32 ce; u32 nfe; u32 fe; + u32 qm_err_type; + u32 dev_err_type; };
struct hisi_qm_err_status { @@ -265,6 +267,8 @@ struct hisi_qm_err_ini { void (*hw_err_disable)(struct hisi_qm *qm); u32 (*get_dev_hw_err_status)(struct hisi_qm *qm); void (*clear_dev_hw_err_status)(struct hisi_qm *qm, u32 err_sts); + void (*disable_error_report)(struct hisi_qm *qm, u32 err_type); + void (*enable_error_report)(struct hisi_qm *qm); void (*open_axi_master_ooo)(struct hisi_qm *qm); void (*close_axi_master_ooo)(struct hisi_qm *qm); void (*open_sva_prefetch)(struct hisi_qm *qm);