From 44503aec0e1f2cd67674fa35f633eb6562690fb1 Mon Sep 17 00:00:00 2001 From: xuzaibo Date: Thu, 11 Jul 2019 14:41:28 +0800 Subject: [PATCH] ACC: Bugfixed while removing VFs with user space tasks on driver inclusion category: bugfix bugzilla: NA CVE: NA [ 686.684022] Call trace: [ 686.684025] __vunmap+0x44/0xf8 [ 686.684026] vunmap+0x24/0x30 [ 686.684030] arch_dma_free+0x84/0xa8 [ 686.684032] dma_direct_free+0x30/0x38 [ 686.684033] dma_free_attrs+0xa0/0xe8 [ 686.684037] uacce_queue_drain+0x12c/0x180 [uacce] [ 686.684039] uacce_fops_flush+0x70/0x80 [uacce] [ 686.684041] filp_close+0x30/0x90 [ 686.684045] put_files_struct+0xf8/0x100 [ 686.684048] exit_files+0x40/0x58 [ 686.684052] do_exit+0x294/0xa18 [ 686.684054] do_group_exit+0x38/0xa0 [ 686.684055] __arm64_sys_exit_group+0x14/0x18 [ 686.684059] el0_svc_common+0x5c/0x100 [ 686.684060] el0_svc_handler+0x2c/0x80 [ 686.684062] el0_svc+0x8/0xc [ 686.684063] ---[ end trace 82054841c5907aec ]--- [ 686.684070] Unable to handle kernel paging request at virtual address ffff00001aee0204 As user tries to disable SRIOV on the PCI device, we try to check whether there is any user including kernel crypto or user space. If any, disabling returns failure. For devices who don't use UACCE, there is no such check. Signed-off-by: xuzaibo Reviewed-by: wangzhou Signed-off-by: lingmingqiang Signed-off-by: Yang Yingliang --- drivers/crypto/hisilicon/hpre/hpre_main.c | 44 ++++++++++++++++++++--- drivers/crypto/hisilicon/qm.c | 28 +++++++++++++++ drivers/crypto/hisilicon/qm.h | 1 + 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 0fefdae80f1f..fac85539af4e 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 d09176bc606d..44ae32b2d3c3 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 092e1188ffaf..cde27eca44ea 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); -- GitLab