mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 00:21:32 +00:00
vfio pull for v3.8
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQx/6fAAoJECObm247sIsi6BgP/1rgXeiDsc4nGcGHHow1h2fS aYbKgNQ9gdRD01fVVeNbkg7XTvpSvfMJ3BK6AxUT2DIT/yAQeSE+To0YtLan6UPq PV1zfShlxEqys3QyCShhOGFZgNZ6b0Auy+7KzKDz1ROBhgbEuteXFuZU3QPQ25AR TWNTTVzcmvdTSvNAUAiyhF5WWuo8yJe0MU4LhXOTRJ2eaMvuNJF+LmRqUCn9c+q4 dUO4eYPQv1YUoVR7RLqJKJ7tvkEI6bcLkOAFKz05v0XBrTdJcIUOIfMSWRlogvKD egwySDVHt0myhno4VS4rV0Pk2KtwlN1isxYmKBe3yuxjwEha6d3SyjaK3MIEtVB+ SU8lllwy7pmk/oUyeaQldxPTFpmKBjWmgyeuU1fJZ57v+tK/M3MZiHP9kTClYIoN TFor87QWIAieDYSIDOH/OrU3nLFrXCR978OpkaceT2guCTP2wxQr8GDfjq/9h42L 3wHFQKdxPezFF468nKIZTU9G+em+bSsDdTCaZvRMMPQrnF4D+sgeUcSOSuWiYzLK Z39Ms6kfsaWssXfks7xHPWQPDw8S2jjwK+V+liBadFgqeiqtwzXfh+R8b1c8YvpX o0uFhQswTbWrp8linNGbdxjRpODVhICEIcDK4UcXTskO1W4J4Y4j2uZrUXLjF9tG PsrsKVGBr541NyvCRKu/ =vfdy -----END PGP SIGNATURE----- Merge tag 'vfio-for-v3.8-v2' of git://github.com/awilliam/linux-vfio Pull vfio update from Alex Williamson. * tag 'vfio-for-v3.8-v2' of git://github.com/awilliam/linux-vfio: vfio-pci: Enable device before attempting reset VFIO: fix out of order labels for error recovery in vfio_pci_init() VFIO: use ACCESS_ONCE() to guard access to dev->driver VFIO: unregister IOMMU notifier on error recovery path vfio-pci: Re-order device reset vfio: simplify kmalloc+copy_from_user to memdup_user
This commit is contained in:
commit
54e37b8dbe
@ -43,6 +43,10 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
|
|||||||
u16 cmd;
|
u16 cmd;
|
||||||
u8 msix_pos;
|
u8 msix_pos;
|
||||||
|
|
||||||
|
ret = pci_enable_device(pdev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
vdev->reset_works = (pci_reset_function(pdev) == 0);
|
vdev->reset_works = (pci_reset_function(pdev) == 0);
|
||||||
pci_save_state(pdev);
|
pci_save_state(pdev);
|
||||||
vdev->pci_saved_state = pci_store_saved_state(pdev);
|
vdev->pci_saved_state = pci_store_saved_state(pdev);
|
||||||
@ -51,8 +55,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
|
|||||||
__func__, dev_name(&pdev->dev));
|
__func__, dev_name(&pdev->dev));
|
||||||
|
|
||||||
ret = vfio_config_init(vdev);
|
ret = vfio_config_init(vdev);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto out;
|
pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state);
|
||||||
|
pci_disable_device(pdev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (likely(!nointxmask))
|
if (likely(!nointxmask))
|
||||||
vdev->pci_2_3 = pci_intx_mask_supported(pdev);
|
vdev->pci_2_3 = pci_intx_mask_supported(pdev);
|
||||||
@ -77,24 +84,15 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
|
|||||||
} else
|
} else
|
||||||
vdev->msix_bar = 0xFF;
|
vdev->msix_bar = 0xFF;
|
||||||
|
|
||||||
ret = pci_enable_device(pdev);
|
return 0;
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(vdev->pci_saved_state);
|
|
||||||
vdev->pci_saved_state = NULL;
|
|
||||||
vfio_config_free(vdev);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_pci_disable(struct vfio_pci_device *vdev)
|
static void vfio_pci_disable(struct vfio_pci_device *vdev)
|
||||||
{
|
{
|
||||||
|
struct pci_dev *pdev = vdev->pdev;
|
||||||
int bar;
|
int bar;
|
||||||
|
|
||||||
pci_disable_device(vdev->pdev);
|
pci_disable_device(pdev);
|
||||||
|
|
||||||
vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE |
|
vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE |
|
||||||
VFIO_IRQ_SET_ACTION_TRIGGER,
|
VFIO_IRQ_SET_ACTION_TRIGGER,
|
||||||
@ -104,22 +102,40 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
|
|||||||
|
|
||||||
vfio_config_free(vdev);
|
vfio_config_free(vdev);
|
||||||
|
|
||||||
pci_reset_function(vdev->pdev);
|
|
||||||
|
|
||||||
if (pci_load_and_free_saved_state(vdev->pdev,
|
|
||||||
&vdev->pci_saved_state) == 0)
|
|
||||||
pci_restore_state(vdev->pdev);
|
|
||||||
else
|
|
||||||
pr_info("%s: Couldn't reload %s saved state\n",
|
|
||||||
__func__, dev_name(&vdev->pdev->dev));
|
|
||||||
|
|
||||||
for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
|
for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
|
||||||
if (!vdev->barmap[bar])
|
if (!vdev->barmap[bar])
|
||||||
continue;
|
continue;
|
||||||
pci_iounmap(vdev->pdev, vdev->barmap[bar]);
|
pci_iounmap(pdev, vdev->barmap[bar]);
|
||||||
pci_release_selected_regions(vdev->pdev, 1 << bar);
|
pci_release_selected_regions(pdev, 1 << bar);
|
||||||
vdev->barmap[bar] = NULL;
|
vdev->barmap[bar] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have saved state, restore it. If we can reset the device,
|
||||||
|
* even better. Resetting with current state seems better than
|
||||||
|
* nothing, but saving and restoring current state without reset
|
||||||
|
* is just busy work.
|
||||||
|
*/
|
||||||
|
if (pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state)) {
|
||||||
|
pr_info("%s: Couldn't reload %s saved state\n",
|
||||||
|
__func__, dev_name(&pdev->dev));
|
||||||
|
|
||||||
|
if (!vdev->reset_works)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_save_state(pdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable INTx and MSI, presumably to avoid spurious interrupts
|
||||||
|
* during reset. Stolen from pci_reset_function()
|
||||||
|
*/
|
||||||
|
pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
|
||||||
|
|
||||||
|
if (vdev->reset_works)
|
||||||
|
__pci_reset_function(pdev);
|
||||||
|
|
||||||
|
pci_restore_state(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_pci_release(void *device_data)
|
static void vfio_pci_release(void *device_data)
|
||||||
@ -327,15 +343,10 @@ static long vfio_pci_ioctl(void *device_data,
|
|||||||
hdr.count > vfio_pci_get_irq_count(vdev, hdr.index))
|
hdr.count > vfio_pci_get_irq_count(vdev, hdr.index))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
data = kmalloc(hdr.count * size, GFP_KERNEL);
|
data = memdup_user((void __user *)(arg + minsz),
|
||||||
if (!data)
|
hdr.count * size);
|
||||||
return -ENOMEM;
|
if (IS_ERR(data))
|
||||||
|
return PTR_ERR(data);
|
||||||
if (copy_from_user(data, (void __user *)(arg + minsz),
|
|
||||||
hdr.count * size)) {
|
|
||||||
kfree(data);
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&vdev->igate);
|
mutex_lock(&vdev->igate);
|
||||||
@ -562,9 +573,9 @@ static int __init vfio_pci_init(void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_virqfd:
|
|
||||||
vfio_pci_virqfd_exit();
|
|
||||||
out_driver:
|
out_driver:
|
||||||
|
vfio_pci_virqfd_exit();
|
||||||
|
out_virqfd:
|
||||||
vfio_pci_uninit_perm_bits();
|
vfio_pci_uninit_perm_bits();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -191,6 +191,17 @@ static void vfio_container_put(struct vfio_container *container)
|
|||||||
kref_put(&container->kref, vfio_container_release);
|
kref_put(&container->kref, vfio_container_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vfio_group_unlock_and_free(struct vfio_group *group)
|
||||||
|
{
|
||||||
|
mutex_unlock(&vfio.group_lock);
|
||||||
|
/*
|
||||||
|
* Unregister outside of lock. A spurious callback is harmless now
|
||||||
|
* that the group is no longer in vfio.group_list.
|
||||||
|
*/
|
||||||
|
iommu_group_unregister_notifier(group->iommu_group, &group->nb);
|
||||||
|
kfree(group);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group objects - create, release, get, put, search
|
* Group objects - create, release, get, put, search
|
||||||
*/
|
*/
|
||||||
@ -229,8 +240,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
|
|||||||
|
|
||||||
minor = vfio_alloc_group_minor(group);
|
minor = vfio_alloc_group_minor(group);
|
||||||
if (minor < 0) {
|
if (minor < 0) {
|
||||||
mutex_unlock(&vfio.group_lock);
|
vfio_group_unlock_and_free(group);
|
||||||
kfree(group);
|
|
||||||
return ERR_PTR(minor);
|
return ERR_PTR(minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,8 +249,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
|
|||||||
if (tmp->iommu_group == iommu_group) {
|
if (tmp->iommu_group == iommu_group) {
|
||||||
vfio_group_get(tmp);
|
vfio_group_get(tmp);
|
||||||
vfio_free_group_minor(minor);
|
vfio_free_group_minor(minor);
|
||||||
mutex_unlock(&vfio.group_lock);
|
vfio_group_unlock_and_free(group);
|
||||||
kfree(group);
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,8 +258,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
|
|||||||
group, "%d", iommu_group_id(iommu_group));
|
group, "%d", iommu_group_id(iommu_group));
|
||||||
if (IS_ERR(dev)) {
|
if (IS_ERR(dev)) {
|
||||||
vfio_free_group_minor(minor);
|
vfio_free_group_minor(minor);
|
||||||
mutex_unlock(&vfio.group_lock);
|
vfio_group_unlock_and_free(group);
|
||||||
kfree(group);
|
|
||||||
return (struct vfio_group *)dev; /* ERR_PTR */
|
return (struct vfio_group *)dev; /* ERR_PTR */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,16 +282,7 @@ static void vfio_group_release(struct kref *kref)
|
|||||||
device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor));
|
device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor));
|
||||||
list_del(&group->vfio_next);
|
list_del(&group->vfio_next);
|
||||||
vfio_free_group_minor(group->minor);
|
vfio_free_group_minor(group->minor);
|
||||||
|
vfio_group_unlock_and_free(group);
|
||||||
mutex_unlock(&vfio.group_lock);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unregister outside of lock. A spurious callback is harmless now
|
|
||||||
* that the group is no longer in vfio.group_list.
|
|
||||||
*/
|
|
||||||
iommu_group_unregister_notifier(group->iommu_group, &group->nb);
|
|
||||||
|
|
||||||
kfree(group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_group_put(struct vfio_group *group)
|
static void vfio_group_put(struct vfio_group *group)
|
||||||
@ -466,8 +465,9 @@ static int vfio_dev_viable(struct device *dev, void *data)
|
|||||||
{
|
{
|
||||||
struct vfio_group *group = data;
|
struct vfio_group *group = data;
|
||||||
struct vfio_device *device;
|
struct vfio_device *device;
|
||||||
|
struct device_driver *drv = ACCESS_ONCE(dev->driver);
|
||||||
|
|
||||||
if (!dev->driver || vfio_whitelisted_driver(dev->driver))
|
if (!drv || vfio_whitelisted_driver(drv))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
device = vfio_group_get_device(group, dev);
|
device = vfio_group_get_device(group, dev);
|
||||||
|
Loading…
Reference in New Issue
Block a user