Pull the check for VM ownership into ppt_find().

This reduces some code duplication.  One behavior change is that
ppt_assign_device() will now only succeed if the device is unowned.
Previously, a device could be assigned to the same VM multiple times,
but each time it was assigned, the device's state was reset.

Reviewed by:	markj, grehan
MFC after:	2 weeks
Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D27301
This commit is contained in:
John Baldwin 2020-11-24 23:56:33 +00:00
parent 1925586e03
commit 908dca3ef4

View File

@ -199,8 +199,8 @@ static devclass_t ppt_devclass;
DEFINE_CLASS_0(ppt, ppt_driver, ppt_methods, sizeof(struct pptdev));
DRIVER_MODULE(ppt, pci, ppt_driver, ppt_devclass, NULL, NULL);
static struct pptdev *
ppt_find(int bus, int slot, int func)
static int
ppt_find(struct vm *vm, int bus, int slot, int func, struct pptdev **pptp)
{
device_t dev;
struct pptdev *ppt;
@ -212,9 +212,15 @@ ppt_find(int bus, int slot, int func)
s = pci_get_slot(dev);
f = pci_get_function(dev);
if (bus == b && slot == s && func == f)
return (ppt);
break;
}
return (NULL);
if (ppt == NULL)
return (ENOENT);
if (ppt->vm != vm) /* Make sure we own this device */
return (EBUSY);
*pptp = ppt;
return (0);
}
static void
@ -378,50 +384,40 @@ int
ppt_assign_device(struct vm *vm, int bus, int slot, int func)
{
struct pptdev *ppt;
int error;
ppt = ppt_find(bus, slot, func);
if (ppt != NULL) {
/*
* If this device is owned by a different VM then we
* cannot change its owner.
*/
if (ppt->vm != NULL && ppt->vm != vm)
return (EBUSY);
/* Passing NULL requires the device to be unowned. */
error = ppt_find(NULL, bus, slot, func, &ppt);
if (error)
return (error);
pci_save_state(ppt->dev);
ppt_pci_reset(ppt->dev);
pci_restore_state(ppt->dev);
ppt->vm = vm;
iommu_add_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
return (0);
}
return (ENOENT);
pci_save_state(ppt->dev);
ppt_pci_reset(ppt->dev);
pci_restore_state(ppt->dev);
ppt->vm = vm;
iommu_add_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
return (0);
}
int
ppt_unassign_device(struct vm *vm, int bus, int slot, int func)
{
struct pptdev *ppt;
int error;
ppt = ppt_find(bus, slot, func);
if (ppt != NULL) {
/*
* If this device is not owned by this 'vm' then bail out.
*/
if (ppt->vm != vm)
return (EBUSY);
error = ppt_find(vm, bus, slot, func, &ppt);
if (error)
return (error);
pci_save_state(ppt->dev);
ppt_pci_reset(ppt->dev);
pci_restore_state(ppt->dev);
ppt_unmap_mmio(vm, ppt);
ppt_teardown_msi(ppt);
ppt_teardown_msix(ppt);
iommu_remove_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
ppt->vm = NULL;
return (0);
}
return (ENOENT);
pci_save_state(ppt->dev);
ppt_pci_reset(ppt->dev);
pci_restore_state(ppt->dev);
ppt_unmap_mmio(vm, ppt);
ppt_teardown_msi(ppt);
ppt_teardown_msix(ppt);
iommu_remove_device(vm_iommu_domain(vm), pci_get_rid(ppt->dev));
ppt->vm = NULL;
return (0);
}
int
@ -452,25 +448,22 @@ ppt_map_mmio(struct vm *vm, int bus, int slot, int func,
struct pptseg *seg;
struct pptdev *ppt;
ppt = ppt_find(bus, slot, func);
if (ppt != NULL) {
if (ppt->vm != vm)
return (EBUSY);
error = ppt_find(vm, bus, slot, func, &ppt);
if (error)
return (error);
for (i = 0; i < MAX_MMIOSEGS; i++) {
seg = &ppt->mmio[i];
if (seg->len == 0) {
error = vm_map_mmio(vm, gpa, len, hpa);
if (error == 0) {
seg->gpa = gpa;
seg->len = len;
}
return (error);
for (i = 0; i < MAX_MMIOSEGS; i++) {
seg = &ppt->mmio[i];
if (seg->len == 0) {
error = vm_map_mmio(vm, gpa, len, hpa);
if (error == 0) {
seg->gpa = gpa;
seg->len = len;
}
return (error);
}
return (ENOSPC);
}
return (ENOENT);
return (ENOSPC);
}
static int
@ -512,11 +505,9 @@ ppt_setup_msi(struct vm *vm, int vcpu, int bus, int slot, int func,
if (numvec < 0 || numvec > MAX_MSIMSGS)
return (EINVAL);
ppt = ppt_find(bus, slot, func);
if (ppt == NULL)
return (ENOENT);
if (ppt->vm != vm) /* Make sure we own this device */
return (EBUSY);
error = ppt_find(vm, bus, slot, func, &ppt);
if (error)
return (error);
/* Reject attempts to enable MSI while MSI-X is active. */
if (ppt->msix.num_msgs != 0 && numvec != 0)
@ -605,11 +596,9 @@ ppt_setup_msix(struct vm *vm, int vcpu, int bus, int slot, int func,
int numvec, alloced, rid, error;
size_t res_size, cookie_size, arg_size;
ppt = ppt_find(bus, slot, func);
if (ppt == NULL)
return (ENOENT);
if (ppt->vm != vm) /* Make sure we own this device */
return (EBUSY);
error = ppt_find(vm, bus, slot, func, &ppt);
if (error)
return (error);
/* Reject attempts to enable MSI-X while MSI is active. */
if (ppt->msi.num_msgs != 0)
@ -713,12 +702,11 @@ int
ppt_disable_msix(struct vm *vm, int bus, int slot, int func)
{
struct pptdev *ppt;
int error;
ppt = ppt_find(bus, slot, func);
if (ppt == NULL)
return (ENOENT);
if (ppt->vm != vm) /* Make sure we own this device */
return (EBUSY);
error = ppt_find(vm, bus, slot, func, &ppt);
if (error)
return (error);
ppt_teardown_msix(ppt);
return (0);