diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 0fefdae80f1f9f139c907540dc4593d87f22e9a7..fac85539af4e3cf2690ebe5ed1cac9569a95aa0b 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -858,9 +857,9 @@ static int hpre_clear_vft_config(struct hpre *hpre) return 0; } +#ifdef CONFIG_PCI_IOV static int hpre_sriov_enable(struct pci_dev *pdev, int max_vfs) { -#ifdef CONFIG_PCI_IOV struct hpre *hpre = pci_get_drvdata(pdev); int pre_existing_vfs, num_vfs, ret; @@ -884,9 +883,31 @@ static int hpre_sriov_enable(struct pci_dev *pdev, int max_vfs) return ret; } return num_vfs; -#else - return 0; -#endif +} + +static int hpre_try_frozen_vfs(struct pci_dev *pdev) +{ + int ret = 0; + struct hpre *hpre, *vf_hpre; + struct pci_dev *dev; + + /* Try to frozen all the VFs as disable SRIOV */ + mutex_lock(&hpre_list_lock); + list_for_each_entry(hpre, &hpre_list, list) { + dev = hpre->qm.pdev; + if (dev == pdev) + continue; + if (pci_physfn(dev) == pdev) { + vf_hpre = pci_get_drvdata(dev); + ret = hisi_qm_frozen(&vf_hpre->qm); + if (ret) + goto frozen_fail; + } + } + +frozen_fail: + mutex_unlock(&hpre_list_lock); + return ret; } static int hpre_sriov_disable(struct pci_dev *pdev) @@ -900,6 +921,16 @@ static int hpre_sriov_disable(struct pci_dev *pdev) return -EPERM; } + /* While VF is in used, SRIOV cannot be disabled. + * However, there is a risk that the behavior is uncertain if the + * device is in hardware resetting. + */ + if (hpre_try_frozen_vfs(pdev)) { + dev_err(&pdev->dev, + "Uacce user space task is using its VF!\n"); + return -EBUSY; + } + /* remove in hpre_pci_driver will be called to free VF resources */ pci_disable_sriov(pdev); return hpre_clear_vft_config(hpre); @@ -912,6 +943,7 @@ static int hpre_sriov_configure(struct pci_dev *pdev, int num_vfs) else return hpre_sriov_enable(pdev, num_vfs); } +#endif static void hpre_log_hw_error(struct hpre *hpre, u32 err_sts) { @@ -1229,7 +1261,9 @@ static struct pci_driver hpre_pci_driver = { .id_table = hpre_dev_ids, .probe = hpre_probe, .remove = hpre_remove, +#ifdef CONFIG_PCI_IOV .sriov_configure = hpre_sriov_configure, +#endif .err_handler = &hpre_err_handler, }; diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index d09176bc606dec70f4f16811a31e2f7b772ca409..44ae32b2d3c309990cae2c7787cb35f6ac0afbea 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -1825,6 +1825,34 @@ void hisi_qm_uninit(struct hisi_qm *qm) } EXPORT_SYMBOL_GPL(hisi_qm_uninit); +/** + * hisi_qm_frozen() - Try to froze QM to cut continuous queue request. If + * there is user on the QM, return failure without doing anything. + * @qm: The qm needed to be fronzen. + * + * This function frozes QM, then we can do SRIOV disabling. + */ +int hisi_qm_frozen(struct hisi_qm *qm) +{ + int ret, i; + + write_lock(&qm->qps_lock); + for (i = 0, ret = 0; i < qm->qp_num; i++) + if (!qm->qp_array[i]) + ret++; + + if (ret == qm->qp_num) { + bitmap_set(qm->qp_bitmap, 0, qm->qp_num); + } else { + write_unlock(&qm->qps_lock); + return -EBUSY; + } + write_unlock(&qm->qps_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_qm_frozen); + /** * hisi_qm_get_vft() - Get vft from a qm. * @qm: The qm we want to get its vft. diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h index 092e1188ffaf380612199741c3a1c9c773b408de..cde27eca44ea9022fe8ebb8a87d16f018b96f682 100644 --- a/drivers/crypto/hisilicon/qm.h +++ b/drivers/crypto/hisilicon/qm.h @@ -305,6 +305,7 @@ struct hisi_qp { int hisi_qm_init(struct hisi_qm *qm); void hisi_qm_uninit(struct hisi_qm *qm); +int hisi_qm_frozen(struct hisi_qm *qm); int hisi_qm_start(struct hisi_qm *qm); int hisi_qm_stop(struct hisi_qm *qm); struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type);