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

Commit 5824f924 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfio-v4.10-rc3' of git://github.com/awilliam/linux-vfio

Pull VFIO fixes from Alex Williamson:
 - Add mtty sample driver properly into build system (Alex Williamson)
 - Restore type1 mapping performance after mdev (Alex Williamson)
 - Fix mdev device race (Alex Williamson)
 - Cleanups to the mdev ABI used by vendor drivers (Alex Williamson)
 - Build fix for old compilers (Arnd Bergmann)
 - Fix sample driver error path (Dan Carpenter)
 - Handle pci_iomap() error (Arvind Yadav)
 - Fix mdev ioctl return type (Paul Gortmaker)

* tag 'vfio-v4.10-rc3' of git://github.com/awilliam/linux-vfio:
  vfio-mdev: fix non-standard ioctl return val causing i386 build fail
  vfio-pci: Handle error from pci_iomap
  vfio-mdev: fix some error codes in the sample code
  vfio-pci: use 32-bit comparisons for register address for gcc-4.5
  vfio-mdev: Make mdev_device private and abstract interfaces
  vfio-mdev: Make mdev_parent private
  vfio-mdev: de-polute the namespace, rename parent_device & parent_ops
  vfio-mdev: Fix remove race
  vfio/type1: Restore mapping performance with mdev support
  vfio-mdev: Fix mtty sample driver building
parents 2fd8774c c6ef7fd4
Loading
Loading
Loading
Loading
+15 −12
Original line number Diff line number Diff line
@@ -127,22 +127,22 @@ the VFIO when devices are unbound from the driver.
Physical Device Driver Interface
--------------------------------

The physical device driver interface provides the parent_ops[3] structure to
define the APIs to manage work in the mediated core driver that is related to
the physical device.
The physical device driver interface provides the mdev_parent_ops[3] structure
to define the APIs to manage work in the mediated core driver that is related
to the physical device.

The structures in the parent_ops structure are as follows:
The structures in the mdev_parent_ops structure are as follows:

* dev_attr_groups: attributes of the parent device
* mdev_attr_groups: attributes of the mediated device
* supported_config: attributes to define supported configurations

The functions in the parent_ops structure are as follows:
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

The callbacks in the parent_ops structure are as follows:
The callbacks in the mdev_parent_ops structure are as follows:

* open: open callback of mediated device
* close: close callback of mediated device
@@ -151,14 +151,14 @@ The callbacks in the parent_ops structure are as follows:
* write: write emulation callback
* mmap: mmap emulation callback

A driver should use the parent_ops structure in the function call to register
itself with the mdev core driver:
A driver should use the mdev_parent_ops structure in the function call to
register itself with the mdev core driver:

extern int  mdev_register_device(struct device *dev,
                                 const struct parent_ops *ops);
                                 const struct mdev_parent_ops *ops);

However, the parent_ops structure is not required in the function call that a
driver should use to unregister itself with the mdev core driver:
However, the mdev_parent_ops structure is not required in the function call
that a driver should use to unregister itself with the mdev core driver:

extern void mdev_unregister_device(struct device *dev);

@@ -223,6 +223,9 @@ Directories and files under the sysfs for Each Physical Device

	sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name);

  (or using mdev_parent_dev(mdev) to arrive at the parent device outside
   of the core mdev code)

* device_api

  This attribute should show which device API is being created, for example,
@@ -394,5 +397,5 @@ References

[1] See Documentation/vfio.txt for more information on VFIO.
[2] struct mdev_driver in include/linux/mdev.h
[3] struct parent_ops in include/linux/mdev.h
[3] struct mdev_parent_ops in include/linux/mdev.h
[4] struct vfio_iommu_driver_ops in include/linux/vfio.h
+12 −12
Original line number Diff line number Diff line
@@ -169,7 +169,7 @@ static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu,

static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn)
{
	struct device *dev = &vgpu->vdev.mdev->dev;
	struct device *dev = mdev_dev(vgpu->vdev.mdev);
	struct gvt_dma *this;
	unsigned long g1;
	int rc;
@@ -198,7 +198,7 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu)
{
	struct gvt_dma *dma;
	struct rb_node *node = NULL;
	struct device *dev = &vgpu->vdev.mdev->dev;
	struct device *dev = mdev_dev(vgpu->vdev.mdev);
	unsigned long gfn;

	mutex_lock(&vgpu->vdev.cache_lock);
@@ -399,7 +399,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
	struct device *pdev;
	void *gvt;

	pdev = mdev->parent->dev;
	pdev = mdev_parent_dev(mdev);
	gvt = kdev_to_i915(pdev)->gvt;

	type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj));
@@ -421,7 +421,7 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
	mdev_set_drvdata(mdev, vgpu);

	gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n",
		     dev_name(&mdev->dev));
		     dev_name(mdev_dev(mdev)));
	return 0;
}

@@ -485,7 +485,7 @@ static int intel_vgpu_open(struct mdev_device *mdev)
	vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier;

	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
	ret = vfio_register_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, &events,
	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, &events,
				&vgpu->vdev.iommu_notifier);
	if (ret != 0) {
		gvt_err("vfio_register_notifier for iommu failed: %d\n", ret);
@@ -493,7 +493,7 @@ static int intel_vgpu_open(struct mdev_device *mdev)
	}

	events = VFIO_GROUP_NOTIFY_SET_KVM;
	ret = vfio_register_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, &events,
	ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, &events,
				&vgpu->vdev.group_notifier);
	if (ret != 0) {
		gvt_err("vfio_register_notifier for group failed: %d\n", ret);
@@ -508,11 +508,11 @@ static int intel_vgpu_open(struct mdev_device *mdev)
	return ret;

undo_group:
	vfio_unregister_notifier(&mdev->dev, VFIO_GROUP_NOTIFY,
	vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
					&vgpu->vdev.group_notifier);

undo_iommu:
	vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY,
	vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
					&vgpu->vdev.iommu_notifier);
out:
	return ret;
@@ -529,11 +529,11 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu)
	if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1))
		return;

	ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY,
	ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_IOMMU_NOTIFY,
					&vgpu->vdev.iommu_notifier);
	WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret);

	ret = vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY,
	ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_GROUP_NOTIFY,
					&vgpu->vdev.group_notifier);
	WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret);

@@ -1111,7 +1111,7 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
	return 0;
}

static const struct parent_ops intel_vgpu_ops = {
static const struct mdev_parent_ops intel_vgpu_ops = {
	.supported_type_groups	= intel_vgpu_type_groups,
	.create			= intel_vgpu_create,
	.remove			= intel_vgpu_remove,
@@ -1398,7 +1398,7 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn)
		return pfn;

	pfn = INTEL_GVT_INVALID_ADDR;
	dev = &info->vgpu->vdev.mdev->dev;
	dev = mdev_dev(info->vgpu->vdev.mdev);
	rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn);
	if (rc != 1) {
		gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc);
+84 −16
Original line number Diff line number Diff line
@@ -27,6 +27,45 @@ static LIST_HEAD(parent_list);
static DEFINE_MUTEX(parent_list_lock);
static struct class_compat *mdev_bus_compat_class;

static LIST_HEAD(mdev_list);
static DEFINE_MUTEX(mdev_list_lock);

struct device *mdev_parent_dev(struct mdev_device *mdev)
{
	return mdev->parent->dev;
}
EXPORT_SYMBOL(mdev_parent_dev);

void *mdev_get_drvdata(struct mdev_device *mdev)
{
	return mdev->driver_data;
}
EXPORT_SYMBOL(mdev_get_drvdata);

void mdev_set_drvdata(struct mdev_device *mdev, void *data)
{
	mdev->driver_data = data;
}
EXPORT_SYMBOL(mdev_set_drvdata);

struct device *mdev_dev(struct mdev_device *mdev)
{
	return &mdev->dev;
}
EXPORT_SYMBOL(mdev_dev);

struct mdev_device *mdev_from_dev(struct device *dev)
{
	return dev_is_mdev(dev) ? to_mdev_device(dev) : NULL;
}
EXPORT_SYMBOL(mdev_from_dev);

uuid_le mdev_uuid(struct mdev_device *mdev)
{
	return mdev->uuid;
}
EXPORT_SYMBOL(mdev_uuid);

static int _find_mdev_device(struct device *dev, void *data)
{
	struct mdev_device *mdev;
@@ -42,7 +81,7 @@ static int _find_mdev_device(struct device *dev, void *data)
	return 0;
}

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

@@ -56,9 +95,9 @@ static bool mdev_device_exist(struct parent_device *parent, uuid_le uuid)
}

/* Should be called holding parent_list_lock */
static struct parent_device *__find_parent_device(struct device *dev)
static struct mdev_parent *__find_parent_device(struct device *dev)
{
	struct parent_device *parent;
	struct mdev_parent *parent;

	list_for_each_entry(parent, &parent_list, next) {
		if (parent->dev == dev)
@@ -69,7 +108,7 @@ static struct parent_device *__find_parent_device(struct device *dev)

static void mdev_release_parent(struct kref *kref)
{
	struct parent_device *parent = container_of(kref, struct parent_device,
	struct mdev_parent *parent = container_of(kref, struct mdev_parent,
						  ref);
	struct device *dev = parent->dev;

@@ -78,7 +117,7 @@ static void mdev_release_parent(struct kref *kref)
}

static
inline struct parent_device *mdev_get_parent(struct parent_device *parent)
inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
{
	if (parent)
		kref_get(&parent->ref);
@@ -86,7 +125,7 @@ inline struct parent_device *mdev_get_parent(struct parent_device *parent)
	return parent;
}

static inline void mdev_put_parent(struct parent_device *parent)
static inline void mdev_put_parent(struct mdev_parent *parent)
{
	if (parent)
		kref_put(&parent->ref, mdev_release_parent);
@@ -95,7 +134,7 @@ static inline void mdev_put_parent(struct parent_device *parent)
static int mdev_device_create_ops(struct kobject *kobj,
				  struct mdev_device *mdev)
{
	struct parent_device *parent = mdev->parent;
	struct mdev_parent *parent = mdev->parent;
	int ret;

	ret = parent->ops->create(kobj, mdev);
@@ -122,7 +161,7 @@ static int mdev_device_create_ops(struct kobject *kobj,
 */
static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove)
{
	struct parent_device *parent = mdev->parent;
	struct mdev_parent *parent = mdev->parent;
	int ret;

	/*
@@ -153,10 +192,10 @@ static int mdev_device_remove_cb(struct device *dev, void *data)
 * Add device to list of registered parent devices.
 * Returns a negative value on error, otherwise 0.
 */
int mdev_register_device(struct device *dev, const struct parent_ops *ops)
int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
{
	int ret;
	struct parent_device *parent;
	struct mdev_parent *parent;

	/* check for mandatory ops */
	if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
@@ -229,7 +268,7 @@ EXPORT_SYMBOL(mdev_register_device);

void mdev_unregister_device(struct device *dev)
{
	struct parent_device *parent;
	struct mdev_parent *parent;
	bool force_remove = true;

	mutex_lock(&parent_list_lock);
@@ -266,7 +305,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
{
	int ret;
	struct mdev_device *mdev;
	struct parent_device *parent;
	struct mdev_parent *parent;
	struct mdev_type *type = to_mdev_type(kobj);

	parent = mdev_get_parent(type->parent);
@@ -316,6 +355,11 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
	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;

create_failed:
@@ -329,12 +373,30 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)

int mdev_device_remove(struct device *dev, bool force_remove)
{
	struct mdev_device *mdev;
	struct parent_device *parent;
	struct mdev_device *mdev, *tmp;
	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;
			break;
		}
	}

	if (found)
		list_del(&mdev->next);

	mutex_unlock(&mdev_list_lock);

	if (!found)
		return -ENODEV;

	type = to_mdev_type(mdev->type_kobj);
	parent = mdev->parent;
	mutex_lock(&parent->lock);
@@ -342,6 +404,11 @@ int mdev_device_remove(struct device *dev, bool force_remove)
	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);

		return ret;
	}

@@ -349,7 +416,8 @@ int mdev_device_remove(struct device *dev, bool force_remove)
	device_unregister(dev);
	mutex_unlock(&parent->lock);
	mdev_put_parent(parent);
	return ret;

	return 0;
}

static int __init mdev_init(void)
+26 −3
Original line number Diff line number Diff line
@@ -16,10 +16,33 @@
int  mdev_bus_register(void);
void mdev_bus_unregister(void);

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

struct mdev_device {
	struct device dev;
	struct mdev_parent *parent;
	uuid_le uuid;
	void *driver_data;
	struct kref ref;
	struct list_head next;
	struct kobject *type_kobj;
};

#define to_mdev_device(dev)	container_of(dev, struct mdev_device, dev)
#define dev_is_mdev(d)		((d)->bus == &mdev_bus_type)

struct mdev_type {
	struct kobject kobj;
	struct kobject *devices_kobj;
	struct parent_device *parent;
	struct mdev_parent *parent;
	struct list_head next;
	struct attribute_group *group;
};
@@ -29,8 +52,8 @@ struct mdev_type {
#define to_mdev_type(_kobj)		\
	container_of(_kobj, struct mdev_type, kobj)

int  parent_create_sysfs_files(struct parent_device *parent);
void parent_remove_sysfs_files(struct parent_device *parent);
int  parent_create_sysfs_files(struct mdev_parent *parent);
void parent_remove_sysfs_files(struct mdev_parent *parent);

int  mdev_create_sysfs_files(struct device *dev, struct mdev_type *type);
void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type);
+4 −4
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ static struct kobj_type mdev_type_ktype = {
	.release = mdev_type_release,
};

struct mdev_type *add_mdev_supported_type(struct parent_device *parent,
struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent,
					  struct attribute_group *group)
{
	struct mdev_type *type;
@@ -158,7 +158,7 @@ static void remove_mdev_supported_type(struct mdev_type *type)
	kobject_put(&type->kobj);
}

static int add_mdev_supported_type_groups(struct parent_device *parent)
static int add_mdev_supported_type_groups(struct mdev_parent *parent)
{
	int i;

@@ -183,7 +183,7 @@ static int add_mdev_supported_type_groups(struct parent_device *parent)
}

/* mdev sysfs functions */
void parent_remove_sysfs_files(struct parent_device *parent)
void parent_remove_sysfs_files(struct mdev_parent *parent)
{
	struct mdev_type *type, *tmp;

@@ -196,7 +196,7 @@ void parent_remove_sysfs_files(struct parent_device *parent)
	kset_unregister(parent->mdev_types_kset);
}

int parent_create_sysfs_files(struct parent_device *parent)
int parent_create_sysfs_files(struct mdev_parent *parent)
{
	int ret;

Loading