From 21b405d1092a9a8f9ae303c73db1b7de0fd9aa81 Mon Sep 17 00:00:00 2001 From: Li Fei1 Date: Wed, 25 Dec 2019 19:41:22 +0800 Subject: [PATCH] hv: vpci: an assign PT device should support FLR or PM reset Before we assign a PT device to post-launched VM, we should reset the PCI device first. However, ACRN hypervisor doesn't plan to support PCIe hot-plug and doesn't support PCIe bridge Secondary Bus Reset. So the PT device must support FLR or PM reset. This patch do this check when assigning a PT device to post-launched VM. Tracked-On: #3465 Signed-off-by: Li Fei1 --- hypervisor/common/hypercall.c | 20 ++++++++++++++++++-- hypervisor/dm/vpci/vpci_priv.h | 2 -- hypervisor/include/dm/vpci.h | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index 2db10328b..351aee2ac 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -827,10 +827,11 @@ int32_t hcall_gpa_to_hpa(struct acrn_vm *vm, uint16_t vmid, uint64_t param) */ int32_t hcall_assign_ptdev(struct acrn_vm *vm, uint16_t vmid, uint64_t param) { - int32_t ret; + int32_t ret = 0; union pci_bdf bdf; struct acrn_vm *target_vm = get_vm_from_vmid(vmid); bool bdf_valid = true; + struct pci_vdev *vdev; if (!is_poweroff_vm(target_vm) && is_postlaunched_vm(target_vm)) { if (param < 0x10000UL) { @@ -845,7 +846,22 @@ int32_t hcall_assign_ptdev(struct acrn_vm *vm, uint16_t vmid, uint64_t param) } if (bdf_valid) { - ret = move_pt_device(vm->iommu, target_vm->iommu, bdf.fields.bus, bdf.fields.devfun); + spinlock_obtain(&vm->vpci.lock); + vdev = pci_find_vdev(&vm->vpci, bdf); + if (vdev == NULL) { + pr_fatal("%s %x:%x.%x not found\n", __func__, bdf.bits.b, bdf.bits.d, bdf.bits.f); + ret = -EPERM; + } else { + /* ToDo: Each PT device must support one type reset */ + if (!vdev->pdev->has_pm_reset && !vdev->pdev->has_flr && !vdev->pdev->has_af_flr) { + pr_fatal("%s %x:%x.%x not support FLR or not support PM reset\n", + __func__, bdf.bits.b, bdf.bits.d, bdf.bits.f); + } + } + spinlock_release(&vm->vpci.lock); + if (ret == 0) { + ret = move_pt_device(vm->iommu, target_vm->iommu, bdf.fields.bus, bdf.fields.devfun); + } } } else { pr_err("%s, target vm is invalid\n", __func__); diff --git a/hypervisor/dm/vpci/vpci_priv.h b/hypervisor/dm/vpci/vpci_priv.h index a272d0ed5..db9acb25f 100644 --- a/hypervisor/dm/vpci/vpci_priv.h +++ b/hypervisor/dm/vpci/vpci_priv.h @@ -143,8 +143,6 @@ void deinit_vmsix(const struct pci_vdev *vdev); uint32_t pci_vdev_read_cfg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes); void pci_vdev_write_cfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t val); -struct pci_vdev *pci_find_vdev(struct acrn_vpci *vpci, union pci_bdf vbdf); - uint32_t pci_vdev_read_bar(const struct pci_vdev *vdev, uint32_t idx); void pci_vdev_write_bar(struct pci_vdev *vdev, uint32_t idx, uint32_t val); #endif /* VPCI_PRIV_H_ */ diff --git a/hypervisor/include/dm/vpci.h b/hypervisor/include/dm/vpci.h index a4eaf6493..c86877a84 100644 --- a/hypervisor/include/dm/vpci.h +++ b/hypervisor/include/dm/vpci.h @@ -130,6 +130,7 @@ struct acrn_vpci { extern const struct pci_vdev_ops vhostbridge_ops; void vpci_init(struct acrn_vm *vm); void vpci_cleanup(struct acrn_vm *vm); +struct pci_vdev *pci_find_vdev(struct acrn_vpci *vpci, union pci_bdf vbdf); void vpci_set_ptdev_intr_info(struct acrn_vm *target_vm, uint16_t vbdf, uint16_t pbdf); void vpci_reset_ptdev_intr_info(struct acrn_vm *target_vm, uint16_t vbdf, uint16_t pbdf);