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 <fei1.li@intel.com>
This commit is contained in:
Li Fei1 2019-12-25 19:41:22 +08:00 committed by wenlingz
parent e74a9f397d
commit 21b405d109
3 changed files with 19 additions and 4 deletions

View File

@ -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 hcall_assign_ptdev(struct acrn_vm *vm, uint16_t vmid, uint64_t param)
{ {
int32_t ret; int32_t ret = 0;
union pci_bdf bdf; union pci_bdf bdf;
struct acrn_vm *target_vm = get_vm_from_vmid(vmid); struct acrn_vm *target_vm = get_vm_from_vmid(vmid);
bool bdf_valid = true; bool bdf_valid = true;
struct pci_vdev *vdev;
if (!is_poweroff_vm(target_vm) && is_postlaunched_vm(target_vm)) { if (!is_poweroff_vm(target_vm) && is_postlaunched_vm(target_vm)) {
if (param < 0x10000UL) { if (param < 0x10000UL) {
@ -845,8 +846,23 @@ int32_t hcall_assign_ptdev(struct acrn_vm *vm, uint16_t vmid, uint64_t param)
} }
if (bdf_valid) { if (bdf_valid) {
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); ret = move_pt_device(vm->iommu, target_vm->iommu, bdf.fields.bus, bdf.fields.devfun);
} }
}
} else { } else {
pr_err("%s, target vm is invalid\n", __func__); pr_err("%s, target vm is invalid\n", __func__);
ret = -EINVAL; ret = -EINVAL;

View File

@ -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); 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); 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); 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); void pci_vdev_write_bar(struct pci_vdev *vdev, uint32_t idx, uint32_t val);
#endif /* VPCI_PRIV_H_ */ #endif /* VPCI_PRIV_H_ */

View File

@ -130,6 +130,7 @@ struct acrn_vpci {
extern const struct pci_vdev_ops vhostbridge_ops; extern const struct pci_vdev_ops vhostbridge_ops;
void vpci_init(struct acrn_vm *vm); void vpci_init(struct acrn_vm *vm);
void vpci_cleanup(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_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); void vpci_reset_ptdev_intr_info(struct acrn_vm *target_vm, uint16_t vbdf, uint16_t pbdf);