diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 60695371fa1a1c905e468e37b823ad31cf9b762e..7aaa6981f98cf2b376c84e2330e8a2c4344ff963 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -111,6 +111,7 @@ #define QM_ABNORMAL_INT_SOURCE 0x100000 #define QM_ABNORMAL_INT_MASK 0x100004 +#define QM_HW_ERROR_IRQ_DISABLE GENMASK(12, 0) #define QM_ABNORMAL_INT_STATUS 0x100008 #define QM_ABNORMAL_INF00 0x100010 #define QM_FIFO_OVERFLOW_TYPE 0xc0 @@ -207,6 +208,7 @@ struct hisi_qm_hw_ops { int (*debug_init)(struct hisi_qm *qm); void (*hw_error_init)(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, u32 msi); + void (*hw_error_uninit)(struct hisi_qm *qm); pci_ers_result_t (*hw_error_handle)(struct hisi_qm *qm); }; @@ -1071,6 +1073,11 @@ static void qm_hw_error_init_v2(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, writel(irq_unmask, qm->io_base + QM_ABNORMAL_INT_MASK); } +static void qm_hw_error_uninit_v2(struct hisi_qm *qm) +{ + writel(QM_HW_ERROR_IRQ_DISABLE, qm->io_base + QM_ABNORMAL_INT_MASK); +} + static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) { const struct hisi_qm_hw_error *err; @@ -1142,6 +1149,7 @@ static const struct hisi_qm_hw_ops qm_hw_ops_v2 = { .qm_db = qm_db_v2, .get_irq_num = qm_get_irq_num_v2, .hw_error_init = qm_hw_error_init_v2, + .hw_error_uninit = qm_hw_error_uninit_v2, .hw_error_handle = qm_hw_error_handle_v2, }; @@ -2643,6 +2651,19 @@ void hisi_qm_hw_error_init(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, } EXPORT_SYMBOL_GPL(hisi_qm_hw_error_init); +void hisi_qm_hw_error_uninit(struct hisi_qm *qm) +{ + if (!qm->ops->hw_error_uninit) { + dev_err(&qm->pdev->dev, + "QM version %d doesn't support hw error handling!\n", + qm->ver); + return; + } + + qm->ops->hw_error_uninit(qm); +} +EXPORT_SYMBOL_GPL(hisi_qm_hw_error_uninit); + /** * hisi_qm_hw_error_handle() - Handle qm non-fatal hardware errors. * @qm: The qm which has non-fatal hardware errors. @@ -2704,6 +2725,19 @@ enum qm_hw_ver hisi_qm_get_hw_version(struct pci_dev *pdev) } EXPORT_SYMBOL_GPL(hisi_qm_get_hw_version); +int hisi_qm_get_hw_error_status(struct hisi_qm *qm) +{ + u32 err_sts; + + err_sts = readl(qm->io_base + QM_ABNORMAL_INT_STATUS) & + QM_ECC_MBIT; + if (err_sts) + return err_sts; + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_qm_get_hw_error_status); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Zhou Wang "); MODULE_DESCRIPTION("HiSilicon Accelerator queue manager driver"); diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h index 1a04ad80e1f07718bdde892aa5641b227d4d9e50..a4bd6295b4b3b06883f456f9f69eabcc49adbfa8 100644 --- a/drivers/crypto/hisilicon/qm.h +++ b/drivers/crypto/hisilicon/qm.h @@ -346,10 +346,12 @@ void hisi_qm_debug_regs_clear(struct hisi_qm *qm); int hisi_qm_debug_init(struct hisi_qm *qm); void hisi_qm_hw_error_init(struct hisi_qm *qm, u32 ce, u32 nfe, u32 fe, u32 msi); +void hisi_qm_hw_error_uninit(struct hisi_qm *qm); pci_ers_result_t hisi_qm_hw_error_handle(struct hisi_qm *qm); void hisi_qm_clear_queues(struct hisi_qm *qm); enum qm_hw_ver hisi_qm_get_hw_version(struct pci_dev *pdev); int hisi_qm_restart(struct hisi_qm *qm); +int hisi_qm_get_hw_error_status(struct hisi_qm *qm); struct hisi_acc_sgl_pool; struct hisi_acc_hw_sgl *hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index d18b0644b6b9e3191d7217103f38b2b4ed2720ac..0c876b74a3f4b1a3f12b30c0389ac586d184a0f0 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -64,6 +64,8 @@ #define HZIP_CORE_INT_SOURCE 0x3010A0 #define HZIP_CORE_INT_MASK 0x3010A4 +#define HZIP_HW_ERROR_IRQ_ENABLE 1 +#define HZIP_HW_ERROR_IRQ_DISABLE 0 #define HZIP_CORE_INT_STATUS 0x3010AC #define HZIP_CORE_INT_STATUS_M_ECC BIT(1) #define HZIP_CORE_SRAM_ECC_ERR_INFO 0x301148 @@ -85,6 +87,9 @@ #define HZIP_SOFT_CTRL_CNT_CLR_CE 0x301000 #define HZIP_SOFT_CTRL_CNT_CLR_CE_BIT BIT(0) +#define HZIP_SOFT_CTRL_ZIP_CONTROL 0x30100C +#define HZIP_AXI_SHUTDOWN_ENABLE BIT(14) +#define HZIP_AXI_SHUTDOWN_DISABLE 0xFFFFBFFF #define HZIP_MSE_ENABLE 1 #define HZIP_MSE_DISABLE 0 @@ -431,6 +436,7 @@ static void hisi_zip_debug_regs_clear(struct hisi_zip *hisi_zip) static void hisi_zip_hw_error_set_state(struct hisi_zip *hisi_zip, bool state) { struct hisi_qm *qm = &hisi_zip->qm; + u32 val; if (qm->ver == QM_HW_V1) { writel(HZIP_CORE_INT_DISABLE, qm->io_base + HZIP_CORE_INT_MASK); @@ -445,17 +451,27 @@ static void hisi_zip_hw_error_set_state(struct hisi_zip *hisi_zip, bool state) writel(HZIP_CORE_INT_RAS_NFE_ENABLE, hisi_zip->qm.io_base + HZIP_CORE_INT_RAS_NFE_ENB); + + val = readl(hisi_zip->qm.io_base + HZIP_SOFT_CTRL_ZIP_CONTROL); if (state) { /* clear ZIP hw error source if having */ writel(HZIP_CORE_INT_DISABLE, hisi_zip->qm.io_base + HZIP_CORE_INT_SOURCE); /* enable ZIP hw error interrupts */ writel(0, hisi_zip->qm.io_base + HZIP_CORE_INT_MASK); + + /* enable ZIP block master OOO when m-bit error occur */ + val = val | HZIP_AXI_SHUTDOWN_ENABLE; } else { /* disable ZIP hw error interrupts */ writel(HZIP_CORE_INT_DISABLE, hisi_zip->qm.io_base + HZIP_CORE_INT_MASK); + + /* disable ZIP block master OOO when m-bit error occur */ + val = val & HZIP_AXI_SHUTDOWN_DISABLE; } + + writel(val, hisi_zip->qm.io_base + HZIP_SOFT_CTRL_ZIP_CONTROL); } static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file) @@ -1323,13 +1339,64 @@ static pci_ers_result_t hisi_zip_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } +static void hisi_zip_set_hw_error(struct hisi_zip *hisi_zip, bool state) +{ + struct pci_dev *pdev = hisi_zip->qm.pdev; + struct hisi_zip *zip = pci_get_drvdata(pci_physfn(pdev)); + struct hisi_qm *qm = &zip->qm; + + if (state) + hisi_qm_hw_error_init(&hisi_zip->qm, QM_BASE_CE, + QM_BASE_NFE | QM_ACC_WB_NOT_READY_TIMEOUT, + 0, QM_DB_RANDOM_INVALID); + else + hisi_qm_hw_error_uninit(qm); + + hisi_zip_hw_error_set_state(zip, state); +} + +static int hisi_zip_get_hw_error_status(struct hisi_zip *hisi_zip) +{ + u32 err_sts; + + err_sts = readl(hisi_zip->qm.io_base + HZIP_CORE_INT_STATUS) & + HZIP_CORE_INT_STATUS_M_ECC; + if (err_sts) + return err_sts; + + return 0; +} + +static int hisi_zip_check_hw_error(struct hisi_zip *hisi_zip) +{ + struct pci_dev *pdev = hisi_zip->qm.pdev; + struct hisi_zip *zip = pci_get_drvdata(pci_physfn(pdev)); + struct hisi_qm *qm = &zip->qm; + int ret; + + ret = hisi_qm_get_hw_error_status(qm); + if (ret) + return ret; + + return hisi_zip_get_hw_error_status(zip); +} + static void hisi_zip_reset_prepare(struct pci_dev *pdev) { struct hisi_zip *hisi_zip = pci_get_drvdata(pdev); struct hisi_qm *qm = &hisi_zip->qm; struct device *dev = &pdev->dev; + u32 delay = 0; int ret; + hisi_zip_set_hw_error(hisi_zip, HZIP_HW_ERROR_IRQ_DISABLE); + + while (hisi_zip_check_hw_error(hisi_zip)) { + msleep(++delay); + if (delay > HZIP_RESET_WAIT_TIMEOUT) + return; + } + ret = hisi_zip_reset_prepare_ready(hisi_zip); if (ret) { dev_err(dev, "FLR not ready!\n"); @@ -1355,6 +1422,14 @@ static void hisi_zip_flr_reset_complete(struct hisi_zip *hisi_zip) { struct pci_dev *pdev = hisi_zip->qm.pdev; struct hisi_zip *zip = pci_get_drvdata(pci_physfn(pdev)); + struct device *dev = &zip->qm.pdev->dev; + u32 id; + + pci_read_config_dword(zip->qm.pdev, PCI_COMMAND, &id); + if (id == ~0) { + hisi_zip_remove(zip->qm.pdev); + dev_err(dev, "Device can not be used!\n"); + } clear_bit(HISI_ZIP_RESET, &zip->status); } @@ -1366,21 +1441,23 @@ static void hisi_zip_reset_done(struct pci_dev *pdev) struct device *dev = &pdev->dev; int ret; + hisi_zip_set_hw_error(hisi_zip, HZIP_HW_ERROR_IRQ_ENABLE); + ret = hisi_qm_restart(qm); if (ret) { dev_err(dev, "Failed to start QM!\n"); - return; + goto flr_done; } if (pdev->is_physfn) { hisi_zip_set_user_domain_and_cache(hisi_zip); - hisi_zip_hw_error_init(hisi_zip); if (hisi_zip->ctrl->num_vfs) hisi_zip_vf_q_assign(hisi_zip, hisi_zip->ctrl->num_vfs); hisi_zip_vf_reset_done(hisi_zip); } +flr_done: hisi_zip_flr_reset_complete(hisi_zip); dev_info(dev, "FLR reset complete\n");