Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 467590e0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfio-v4.18-rc1' of git://github.com/awilliam/linux-vfio

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
parents 763f9694 c1abca96
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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
+36 −66
Original line number Diff line number Diff line
@@ -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)
{
@@ -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;
@@ -297,6 +268,10 @@ 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);
}
@@ -304,7 +279,7 @@ static void mdev_device_release(struct device *dev)
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);

@@ -312,21 +287,28 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
	if (!parent)
		return -EINVAL;

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

	/* Check for duplicate */
	if (mdev_device_exist(parent, uuid)) {
	list_for_each_entry(tmp, &mdev_list, next) {
		if (!uuid_le_cmp(tmp->uuid, uuid)) {
			mutex_unlock(&mdev_list_lock);
			ret = -EEXIST;
		goto create_err;
			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);

@@ -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;
}
@@ -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;
	}

	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;
+1 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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)
+7 −7
Original line number Diff line number Diff line
@@ -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;
}

+22 −8
Original line number Diff line number Diff line
@@ -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>
@@ -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);
	}
@@ -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",
@@ -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);
@@ -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;
}
@@ -673,7 +680,7 @@ 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;
	}
@@ -681,18 +688,24 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,
	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);

@@ -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);
	}
Loading