Skip to content

Commit

Permalink
Merge tag 'vfio-v4.18-rc1' of git://github.com/awilliam/linux-vfio
Browse files Browse the repository at this point in the history
Pull VFIO updates from Alex Williamson:

 - Bind type1 task tracking to group_leader to facilitate vCPU hotplug
   in QEMU (Alex Williamson)

 - Sample mdev display drivers, including region-based host and guest
   Linux drivers and bochs compatible dmabuf device
   (Gerd Hoffmann)

 - Fix vfio-platform reset module leak (Geert Uytterhoeven)

 - vfio-platform error message consistency (Geert Uytterhoeven)

 - Global checking for mdev uuid collisions rather than per parent
   device (Alex Williamson)

 - Use match_string() helper (Yisheng Xie)

 - vfio-platform PM domain fixes (Geert Uytterhoeven)

 - Fix sample mbochs driver build dependency (Arnd Bergmann)

* tag 'vfio-v4.18-rc1' of git://github.com/awilliam/linux-vfio:
  samples: mbochs: add DMA_SHARED_BUFFER dependency
  vfio: platform: Fix using devices in PM Domains
  vfio: use match_string() helper
  vfio/mdev: Re-order sysfs attribute creation
  vfio/mdev: Check globally for duplicate devices
  vfio: platform: Make printed error messages more consistent
  vfio: platform: Fix reset module leak in error path
  sample: vfio bochs vbe display (host device for bochs-drm)
  sample: vfio mdev display - guest driver
  sample: vfio mdev display - host device
  vfio/type1: Fix task tracking for QEMU vCPU hotplug
  • Loading branch information
torvalds committed Jun 12, 2018
2 parents 763f969 + c1abca9 commit 467590e
Show file tree
Hide file tree
Showing 13 changed files with 2,622 additions and 116 deletions.
5 changes: 5 additions & 0 deletions Documentation/vfio-mediated-device.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ The functions in the mdev_parent_ops structure are as follows:
* create: allocate basic resources in a driver for a mediated device
* remove: free resources in a driver when a mediated device is destroyed

(Note that mdev-core provides no implicit serialization of create/remove
callbacks per mdev parent device, per mdev type, or any other categorization.
Vendor drivers are expected to be fully asynchronous in this respect or
provide their own internal resource protection.)

The callbacks in the mdev_parent_ops structure are as follows:

* open: open callback of mediated device
Expand Down
102 changes: 36 additions & 66 deletions drivers/vfio/mdev/mdev_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,34 +66,6 @@ uuid_le mdev_uuid(struct mdev_device *mdev)
}
EXPORT_SYMBOL(mdev_uuid);

static int _find_mdev_device(struct device *dev, void *data)
{
struct mdev_device *mdev;

if (!dev_is_mdev(dev))
return 0;

mdev = to_mdev_device(dev);

if (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0)
return 1;

return 0;
}

static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid)
{
struct device *dev;

dev = device_find_child(parent->dev, &uuid, _find_mdev_device);
if (dev) {
put_device(dev);
return true;
}

return false;
}

/* Should be called holding parent_list_lock */
static struct mdev_parent *__find_parent_device(struct device *dev)
{
Expand Down Expand Up @@ -221,7 +193,6 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
}

kref_init(&parent->ref);
mutex_init(&parent->lock);

parent->dev = dev;
parent->ops = ops;
Expand Down Expand Up @@ -297,36 +268,47 @@ static void mdev_device_release(struct device *dev)
{
struct mdev_device *mdev = to_mdev_device(dev);

mutex_lock(&mdev_list_lock);
list_del(&mdev->next);
mutex_unlock(&mdev_list_lock);

dev_dbg(&mdev->dev, "MDEV: destroying\n");
kfree(mdev);
}

int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
{
int ret;
struct mdev_device *mdev;
struct mdev_device *mdev, *tmp;
struct mdev_parent *parent;
struct mdev_type *type = to_mdev_type(kobj);

parent = mdev_get_parent(type->parent);
if (!parent)
return -EINVAL;

mutex_lock(&parent->lock);
mutex_lock(&mdev_list_lock);

/* Check for duplicate */
if (mdev_device_exist(parent, uuid)) {
ret = -EEXIST;
goto create_err;
list_for_each_entry(tmp, &mdev_list, next) {
if (!uuid_le_cmp(tmp->uuid, uuid)) {
mutex_unlock(&mdev_list_lock);
ret = -EEXIST;
goto mdev_fail;
}
}

mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
if (!mdev) {
mutex_unlock(&mdev_list_lock);
ret = -ENOMEM;
goto create_err;
goto mdev_fail;
}

memcpy(&mdev->uuid, &uuid, sizeof(uuid_le));
list_add(&mdev->next, &mdev_list);
mutex_unlock(&mdev_list_lock);

mdev->parent = parent;
kref_init(&mdev->ref);

Expand All @@ -338,35 +320,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
ret = device_register(&mdev->dev);
if (ret) {
put_device(&mdev->dev);
goto create_err;
goto mdev_fail;
}

ret = mdev_device_create_ops(kobj, mdev);
if (ret)
goto create_failed;
goto create_fail;

ret = mdev_create_sysfs_files(&mdev->dev, type);
if (ret) {
mdev_device_remove_ops(mdev, true);
goto create_failed;
goto create_fail;
}

mdev->type_kobj = kobj;
mdev->active = true;
dev_dbg(&mdev->dev, "MDEV: created\n");

mutex_unlock(&parent->lock);

mutex_lock(&mdev_list_lock);
list_add(&mdev->next, &mdev_list);
mutex_unlock(&mdev_list_lock);

return ret;
return 0;

create_failed:
create_fail:
device_unregister(&mdev->dev);

create_err:
mutex_unlock(&parent->lock);
mdev_fail:
mdev_put_parent(parent);
return ret;
}
Expand All @@ -377,44 +352,39 @@ int mdev_device_remove(struct device *dev, bool force_remove)
struct mdev_parent *parent;
struct mdev_type *type;
int ret;
bool found = false;

mdev = to_mdev_device(dev);

mutex_lock(&mdev_list_lock);
list_for_each_entry(tmp, &mdev_list, next) {
if (tmp == mdev) {
found = true;
if (tmp == mdev)
break;
}
}

if (found)
list_del(&mdev->next);
if (tmp != mdev) {
mutex_unlock(&mdev_list_lock);
return -ENODEV;
}

mutex_unlock(&mdev_list_lock);
if (!mdev->active) {
mutex_unlock(&mdev_list_lock);
return -EAGAIN;
}

if (!found)
return -ENODEV;
mdev->active = false;
mutex_unlock(&mdev_list_lock);

type = to_mdev_type(mdev->type_kobj);
parent = mdev->parent;
mutex_lock(&parent->lock);

ret = mdev_device_remove_ops(mdev, force_remove);
if (ret) {
mutex_unlock(&parent->lock);

mutex_lock(&mdev_list_lock);
list_add(&mdev->next, &mdev_list);
mutex_unlock(&mdev_list_lock);

mdev->active = true;
return ret;
}

mdev_remove_sysfs_files(dev, type);
device_unregister(dev);
mutex_unlock(&parent->lock);
mdev_put_parent(parent);

return 0;
Expand Down
2 changes: 1 addition & 1 deletion drivers/vfio/mdev/mdev_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ struct mdev_parent {
struct device *dev;
const struct mdev_parent_ops *ops;
struct kref ref;
struct mutex lock;
struct list_head next;
struct kset *mdev_types_kset;
struct list_head type_list;
Expand All @@ -34,6 +33,7 @@ struct mdev_device {
struct kref ref;
struct list_head next;
struct kobject *type_kobj;
bool active;
};

#define to_mdev_device(dev) container_of(dev, struct mdev_device, dev)
Expand Down
14 changes: 7 additions & 7 deletions drivers/vfio/mdev/mdev_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,24 +257,24 @@ int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type)
{
int ret;

ret = sysfs_create_files(&dev->kobj, mdev_device_attrs);
if (ret)
return ret;

ret = sysfs_create_link(type->devices_kobj, &dev->kobj, dev_name(dev));
if (ret)
goto device_link_failed;
return ret;

ret = sysfs_create_link(&dev->kobj, &type->kobj, "mdev_type");
if (ret)
goto type_link_failed;

ret = sysfs_create_files(&dev->kobj, mdev_device_attrs);
if (ret)
goto create_files_failed;

return ret;

create_files_failed:
sysfs_remove_link(&dev->kobj, "mdev_type");
type_link_failed:
sysfs_remove_link(type->devices_kobj, dev_name(dev));
device_link_failed:
sysfs_remove_files(&dev->kobj, mdev_device_attrs);
return ret;
}

Expand Down
30 changes: 22 additions & 8 deletions drivers/vfio/platform/vfio_platform_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/iommu.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
Expand Down Expand Up @@ -239,6 +240,7 @@ static void vfio_platform_release(void *device_data)
ret, extra_dbg ? extra_dbg : "");
WARN_ON(1);
}
pm_runtime_put(vdev->device);
vfio_platform_regions_cleanup(vdev);
vfio_platform_irq_cleanup(vdev);
}
Expand Down Expand Up @@ -269,6 +271,10 @@ static int vfio_platform_open(void *device_data)
if (ret)
goto err_irq;

ret = pm_runtime_get_sync(vdev->device);
if (ret < 0)
goto err_pm;

ret = vfio_platform_call_reset(vdev, &extra_dbg);
if (ret && vdev->reset_required) {
dev_warn(vdev->device, "reset driver is required and reset call failed in open (%d) %s\n",
Expand All @@ -283,6 +289,8 @@ static int vfio_platform_open(void *device_data)
return 0;

err_rst:
pm_runtime_put(vdev->device);
err_pm:
vfio_platform_irq_cleanup(vdev);
err_irq:
vfio_platform_regions_cleanup(vdev);
Expand Down Expand Up @@ -630,8 +638,7 @@ static int vfio_platform_of_probe(struct vfio_platform_device *vdev,
ret = device_property_read_string(dev, "compatible",
&vdev->compat);
if (ret)
pr_err("VFIO: cannot retrieve compat for %s\n",
vdev->name);
pr_err("VFIO: Cannot retrieve compat for %s\n", vdev->name);

return ret;
}
Expand Down Expand Up @@ -673,26 +680,32 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,

ret = vfio_platform_get_reset(vdev);
if (ret && vdev->reset_required) {
pr_err("vfio: no reset function found for device %s\n",
pr_err("VFIO: No reset function found for device %s\n",
vdev->name);
return ret;
}

group = vfio_iommu_group_get(dev);
if (!group) {
pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
return -EINVAL;
ret = -EINVAL;
goto put_reset;
}

ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev);
if (ret) {
vfio_iommu_group_put(group, dev);
return ret;
}
if (ret)
goto put_iommu;

mutex_init(&vdev->igate);

pm_runtime_enable(vdev->device);
return 0;

put_iommu:
vfio_iommu_group_put(group, dev);
put_reset:
vfio_platform_put_reset(vdev);
return ret;
}
EXPORT_SYMBOL_GPL(vfio_platform_probe_common);

Expand All @@ -703,6 +716,7 @@ struct vfio_platform_device *vfio_platform_remove_common(struct device *dev)
vdev = vfio_del_group_dev(dev);

if (vdev) {
pm_runtime_disable(vdev->device);
vfio_platform_put_reset(vdev);
vfio_iommu_group_put(dev->iommu_group, dev);
}
Expand Down
11 changes: 3 additions & 8 deletions drivers/vfio/vfio.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,21 +630,16 @@ static const char * const vfio_driver_whitelist[] = { "pci-stub" };

static bool vfio_dev_whitelisted(struct device *dev, struct device_driver *drv)
{
int i;

if (dev_is_pci(dev)) {
struct pci_dev *pdev = to_pci_dev(dev);

if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
return true;
}

for (i = 0; i < ARRAY_SIZE(vfio_driver_whitelist); i++) {
if (!strcmp(drv->name, vfio_driver_whitelist[i]))
return true;
}

return false;
return match_string(vfio_driver_whitelist,
ARRAY_SIZE(vfio_driver_whitelist),
drv->name) >= 0;
}

/*
Expand Down
Loading

0 comments on commit 467590e

Please sign in to comment.