]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
crypto: hisilicon/qm - support function-level error reset
authorZhushuai Yin <yinzhushuai@huawei.com>
Mon, 18 May 2026 14:29:53 +0000 (22:29 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 29 May 2026 05:54:43 +0000 (13:54 +0800)
When executing operations on crypto devices, hardware errors
are inevitable. For certain errors, a full device reset is
required to recover. However, in certain cases, only a
specific function may fail, while other functions can still
operate normally. A system-wide RAS reset in such cases would
unnecessarily impact functioning components.

This patch introduces function-level granularity handling,
enabling targeted resets of only the error-reporting
functions without affecting other operational functions.

Signed-off-by: Zhushuai Yin <yinzhushuai@huawei.com>
Signed-off-by: Zongyu Wu <wuzongyu1@huawei.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/hisilicon/qm.c
include/linux/hisi_acc_qm.h

index 71af462daf5be677387a992cd04aa819b8409289..2b3132595e427013352b359a637f7e1f62dcf278 100644 (file)
 #define QM_QOS_MAX_CIR_U               6
 #define QM_AUTOSUSPEND_DELAY           3000
 
+/* qm function err mask */
+#define QM_FUNC_AXI_ERR_ST0            0x100280
+#define QM_RAS_FUNC_ERROR              (BIT(0) | BIT(1))
+#define QM_FUNC_RAS_CLEAR_ALL          GENMASK(63, 0)
+
 /* qm isolation state mask */
 #define QM_ISOLATED_STATE              BIT(31)
 #define QM_ISOLATED_THRESHOLD_MASK     GENMASK(15, 0)
@@ -314,6 +319,7 @@ enum qm_ifc_cmd {
        QM_VF_START_FAIL,
        QM_PF_SET_QOS,
        QM_VF_GET_QOS,
+       QM_FUNCTION_RESET,
        QM_VF_GET_ISOLATE,
        QM_PF_SET_ISOLATE,
 };
@@ -493,6 +499,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 void hisi_qm_stop_qp(struct hisi_qp *qp);
+static int qm_restart(struct hisi_qm *qm);
 
 int hisi_qm_q_num_set(const char *val, const struct kernel_param *kp,
                      unsigned int device)
@@ -1171,18 +1178,20 @@ static void qm_reset_function(struct hisi_qm *qm)
                return;
        }
 
+       dev_info(dev, "function reset start...\n");
        ret = hisi_qm_stop(qm, QM_DOWN);
        if (ret) {
                dev_err(dev, "failed to stop qm when reset function\n");
                goto clear_bit;
        }
 
-       ret = hisi_qm_start(qm);
+       ret = qm_restart(qm);
        if (ret)
                dev_err(dev, "failed to start qm when reset function\n");
 
 clear_bit:
        qm_reset_bit_clear(qm);
+       dev_info(dev, "function reset end...\n");
 }
 
 static irqreturn_t qm_aeq_thread(int irq, void *data)
@@ -1505,6 +1514,8 @@ static void qm_hw_error_cfg(struct hisi_qm *qm)
        qm->error_mask = qm_err->nfe | qm_err->ce | qm_err->fe;
        /* clear QM hw residual error source */
        writel(qm->error_mask, qm->io_base + QM_ABNORMAL_INT_SOURCE);
+       if (qm->ver >= QM_HW_V5)
+               writeq(QM_FUNC_RAS_CLEAR_ALL, qm->io_base + QM_FUNC_AXI_ERR_ST0);
 
        /* configure error type */
        writel(qm_err->ce, qm->io_base + QM_RAS_CE_ENABLE);
@@ -1610,6 +1621,15 @@ static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm)
                        qm->err_status.is_qm_ecc_mbit = true;
 
                qm_log_hw_error(qm, error_status);
+               /* Trigger func reset only when error is detected in bit 0 or bit 1. */
+               if ((qm->ver >= QM_HW_V5) &&
+                   (error_status & QM_RAS_FUNC_ERROR) &&
+                   (error_status & qm_err->reset_mask) == 0) {
+                       writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE);
+                       writel(qm_err->nfe, qm->io_base + QM_RAS_NFE_ENABLE);
+                       return ACC_ERR_NEED_FUNC_RESET;
+               }
+
                if (error_status & qm_err->reset_mask) {
                        /* Disable the same error reporting until device is recovered. */
                        writel(qm_err->nfe & (~error_status), qm->io_base + QM_RAS_NFE_ENABLE);
@@ -4364,10 +4384,13 @@ static enum acc_err_result qm_process_dev_error(struct hisi_qm *qm)
 
        /* log device error */
        dev_ret = qm_dev_err_handle(qm);
+       if (qm_ret == ACC_ERR_NEED_RESET || dev_ret == ACC_ERR_NEED_RESET)
+               return ACC_ERR_NEED_RESET;
+
+       if (qm_ret == ACC_ERR_NEED_FUNC_RESET)
+               return ACC_ERR_NEED_FUNC_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;
 }
 
 /**
@@ -4392,7 +4415,7 @@ pci_ers_result_t hisi_qm_dev_err_detected(struct pci_dev *pdev,
                return PCI_ERS_RESULT_DISCONNECT;
 
        ret = qm_process_dev_error(qm);
-       if (ret == ACC_ERR_NEED_RESET)
+       if (ret == ACC_ERR_NEED_RESET || ret == ACC_ERR_NEED_FUNC_RESET)
                return PCI_ERS_RESULT_NEED_RESET;
 
        return PCI_ERS_RESULT_RECOVERED;
@@ -5119,9 +5142,53 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev)
 }
 EXPORT_SYMBOL_GPL(hisi_qm_dev_shutdown);
 
+static u64 qm_get_function_mask(struct hisi_qm *qm)
+{
+       return readq(qm->io_base + QM_FUNC_AXI_ERR_ST0);
+}
+
+static void qm_clear_function_mask(struct hisi_qm *qm, u64 func_mask)
+{
+       /* Register write 1 clear */
+       writeq(func_mask, qm->io_base + QM_FUNC_AXI_ERR_ST0);
+}
+
+static void qm_function_reset(struct hisi_qm *qm)
+{
+       struct device *dev = &qm->pdev->dev;
+       u64 func_mask;
+       u32 fun_num;
+       int ret;
+
+       func_mask = qm_get_function_mask(qm);
+       if (!func_mask) {
+               dev_info(dev, "no function need reset!\n");
+               return;
+       }
+
+       for (fun_num = 1; fun_num <= qm->vfs_num; fun_num++) {
+               if (func_mask & BIT(fun_num)) {
+                       ret = qm_ping_single_vf(qm, QM_FUNCTION_RESET, 0, fun_num);
+                       /* When function ping fail, user decides the VF reset method. */
+                       if (ret)
+                               dev_err(dev, "failed to send command(0x%x) to VF(%u)!\n",
+                                       (unsigned int)QM_FUNCTION_RESET, fun_num);
+               }
+       }
+
+       if (func_mask & BIT(0)) {
+               dev_info(dev, "function reset start...\n");
+               qm_reset_function(qm);
+               dev_info(dev, "function reset end!\n");
+       }
+
+       qm_clear_function_mask(qm, func_mask);
+}
+
 static void hisi_qm_controller_reset(struct work_struct *rst_work)
 {
        struct hisi_qm *qm = container_of(rst_work, struct hisi_qm, rst_work);
+       enum acc_err_result err_result;
        int ret;
 
        ret = qm_pm_get_sync(qm);
@@ -5130,9 +5197,11 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work)
                return;
        }
 
-       ret = qm_process_dev_error(qm);
-       if (ret == ACC_ERR_NEED_RESET)
+       err_result = qm_process_dev_error(qm);
+       if (err_result == ACC_ERR_NEED_RESET)
                (void)qm_controller_reset(qm);
+       else if (err_result == ACC_ERR_NEED_FUNC_RESET)
+               qm_function_reset(qm);
 
        qm_pm_put_sync(qm);
 }
@@ -5179,7 +5248,7 @@ static void qm_pf_reset_vf_done(struct hisi_qm *qm)
        int ret;
 
        pci_restore_state(pdev);
-       ret = hisi_qm_start(qm);
+       ret = qm_restart(qm);
        if (ret) {
                dev_err(&pdev->dev, "failed to start QM, ret = %d.\n", ret);
                cmd = QM_VF_START_FAIL;
@@ -5323,6 +5392,11 @@ static void qm_handle_cmd_msg(struct hisi_qm *qm, u32 fun_num)
        case QM_PF_SET_QOS:
                qm->mb_qos = data;
                break;
+       case QM_FUNCTION_RESET:
+               dev_info(dev, "function reset start...\n");
+               qm_reset_function(qm);
+               dev_info(dev, "function reset end!\n");
+               break;
        case QM_VF_GET_ISOLATE:
                /* Read the isolation policy of the PF during VF initialization. */
                qm_vf_get_isolate_data(qm, fun_num);
index 98ff6bcfdebed97618f0a0b070dbfa8dd6398b9c..0a2da1029a3fb81a56d0c4989e146688d25976e2 100644 (file)
@@ -248,6 +248,7 @@ enum acc_err_result {
        ACC_ERR_NONE,
        ACC_ERR_NEED_RESET,
        ACC_ERR_RECOVERED,
+       ACC_ERR_NEED_FUNC_RESET,
 };
 
 struct hisi_qm_err_mask {