static int sec_probe_init(struct hisi_qm *qm, struct sec_dev *sec)
 {
+       int ret;
+
+       /*
+        * WQ_HIGHPRI: SEC request must be low delayed,
+        * so need a high priority workqueue.
+        * WQ_UNBOUND: SEC task is likely with long
+        * running CPU intensive workloads.
+        */
+       qm->wq = alloc_workqueue("%s", WQ_HIGHPRI |
+               WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus(),
+               pci_name(qm->pdev));
+       if (!qm->wq) {
+               pci_err(qm->pdev, "fail to alloc workqueue\n");
+               return -ENOMEM;
+       }
+
        if (qm->fun_type == QM_HW_PF) {
                qm->qp_base = SEC_PF_DEF_Q_BASE;
                qm->qp_num = pf_q_num;
                qm->debug.curr_qm_qp_num = pf_q_num;
 
-               return sec_pf_probe_init(sec);
+               ret = sec_pf_probe_init(sec);
+               if (ret)
+                       goto err_probe_uninit;
        } else if (qm->fun_type == QM_HW_VF) {
                /*
                 * have no way to get qm configure in VM in v1 hardware,
                        qm->qp_num = SEC_QUEUE_NUM_V1 - SEC_PF_DEF_Q_NUM;
                } else if (qm->ver == QM_HW_V2) {
                        /* v2 starts to support get vft by mailbox */
-                       return hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num);
+                       ret = hisi_qm_get_vft(qm, &qm->qp_base, &qm->qp_num);
+                       if (ret)
+                               goto err_probe_uninit;
                }
        } else {
-               return -ENODEV;
+               ret = -ENODEV;
+               goto err_probe_uninit;
        }
 
        return 0;
+err_probe_uninit:
+       destroy_workqueue(qm->wq);
+       return ret;
 }
 
 static void sec_probe_uninit(struct hisi_qm *qm)
 {
        hisi_qm_dev_err_uninit(qm);
+
+       destroy_workqueue(qm->wq);
 }
 
 static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)