driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I9CB6L 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 (cherry picked from commit 6cf358afff7be27d3cd89b72737cbcc5427ff71b) --- 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 6bd3d8277d47..af077934c1a5 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -1290,11 +1290,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) @@ -1334,6 +1349,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 939fb633e481..5883e56e26e4 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -390,7 +390,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); };
@@ -1449,24 +1449,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; @@ -3286,14 +3297,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); }
/** @@ -3915,17 +3926,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; @@ -3933,11 +3946,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; @@ -3946,16 +3969,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; }
/** @@ -4160,8 +4192,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; }
@@ -4421,6 +4451,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) { @@ -4494,6 +4525,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 6c09857e2b82..566581039c87 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -1010,11 +1010,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) @@ -1052,6 +1066,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 21cf1401cbc3..59f7b9fdb816 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -1068,11 +1068,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) @@ -1129,6 +1143,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 d7527371c915..4e4f96cff387 100644 --- a/include/linux/hisi_acc_qm.h +++ b/include/linux/hisi_acc_qm.h @@ -241,6 +241,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 { @@ -254,6 +256,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);