diff mbox

[v7,1/4] vfio: Mediated device Core driver

Message ID 57E13009.6020405@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jike Song Sept. 20, 2016, 12:48 p.m. UTC
On 08/25/2016 11:53 AM, Kirti Wankhede wrote:
/* {snip} */

To show a straight-forward way of introducing an independent
struct device for the middle layer (in Kirti's patch the parent device,
we changed it to mdev_host since 'parent' is something too
generic or misleading) between physical device and mdev devices,
and how it will make the whole thing simpler, here is the incremental patch
against Kirti's version 7, which is exactly the same as the
the standalone version sent out Sep02.

This is only for demonstration. The sysfs interfaces changes are
kept although there are lots of discussions since.

--
Thanks,
Jike




--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index 4a23c13..7c70753 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -7,4 +7,4 @@  obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
 obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o
 obj-$(CONFIG_VFIO_PCI) += pci/
 obj-$(CONFIG_VFIO_PLATFORM) += platform/
-obj-$(CONFIG_VFIO_MDEV) += mdev/
+obj-$(CONFIG_MDEV) += mdev/
diff --git a/drivers/vfio/mdev/Kconfig b/drivers/vfio/mdev/Kconfig
index 703abd0..d25439f 100644
--- a/drivers/vfio/mdev/Kconfig
+++ b/drivers/vfio/mdev/Kconfig
@@ -1,5 +1,5 @@ 
 
-config VFIO_MDEV
+config MDEV
     tristate "Mediated device driver framework"
     depends on VFIO
     default n
@@ -8,11 +8,3 @@  config VFIO_MDEV
 	See Documentation/vfio-mediated-device.txt for more details.
 
         If you don't know what do here, say N.
-
-config VFIO_MDEV_DEVICE
-    tristate "VFIO support for Mediated devices"
-    depends on VFIO && VFIO_MDEV
-    default n
-    help
-        VFIO based driver for mediated devices.
-
diff --git a/drivers/vfio/mdev/Makefile b/drivers/vfio/mdev/Makefile
index e5087ed..8bd78b5 100644
--- a/drivers/vfio/mdev/Makefile
+++ b/drivers/vfio/mdev/Makefile
@@ -1,6 +1,4 @@ 
 
 mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o
 
-obj-$(CONFIG_VFIO_MDEV) += mdev.o
-obj-$(CONFIG_VFIO_MDEV_DEVICE) += vfio_mdev.o
-
+obj-$(CONFIG_MDEV) += mdev.o
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index 9f278c7..cb27ccf 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -5,6 +5,11 @@ 
  *     Author: Neo Jia <cjia@nvidia.com>
  *	       Kirti Wankhede <kwankhede@nvidia.com>
  *
+ * Copyright (c) 2016 Intel Corporation.
+ * Author:
+ *	Xiao Guangrong <guangrong.xiao@linux.intel.com>
+ *	Jike Song <jike.song@intel.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -23,316 +28,144 @@ 
 
 #include "mdev_private.h"
 
-#define DRIVER_VERSION		"0.1"
+#define DRIVER_VERSION		"0.2"
 #define DRIVER_AUTHOR		"NVIDIA Corporation"
-#define DRIVER_DESC		"Mediated device Core Driver"
-
-static LIST_HEAD(parent_list);
-static DEFINE_MUTEX(parent_list_lock);
-
-static int mdev_add_attribute_group(struct device *dev,
-				    const struct attribute_group **groups)
-{
-	return sysfs_create_groups(&dev->kobj, groups);
-}
-
-static void mdev_remove_attribute_group(struct device *dev,
-					const struct attribute_group **groups)
-{
-	sysfs_remove_groups(&dev->kobj, groups);
-}
-
-/* Should be called holding parent->mdev_list_lock */
-static struct mdev_device *__find_mdev_device(struct parent_device *parent,
-					      uuid_le uuid)
-{
-	struct mdev_device *mdev;
-
-	list_for_each_entry(mdev, &parent->mdev_list, next) {
-		if (uuid_le_cmp(mdev->uuid, uuid) == 0)
-			return mdev;
-	}
-	return NULL;
-}
-
-/* Should be called holding parent_list_lock */
-static struct parent_device *__find_parent_device(struct device *dev)
-{
-	struct parent_device *parent;
-
-	list_for_each_entry(parent, &parent_list, next) {
-		if (parent->dev == dev)
-			return parent;
-	}
-	return NULL;
-}
+#define DRIVER_DESC		"Mediated Device Core Driver"
 
-static void mdev_release_parent(struct kref *kref)
-{
-	struct parent_device *parent = container_of(kref, struct parent_device,
-						    ref);
-	kfree(parent);
-}
 
-static
-inline struct parent_device *mdev_get_parent(struct parent_device *parent)
+static int __find_mdev_device(struct device *dev, void *data)
 {
-	if (parent)
-		kref_get(&parent->ref);
-
-	return parent;
-}
+	struct mdev_device *mdev = dev_to_mdev(dev);
 
-static inline void mdev_put_parent(struct parent_device *parent)
-{
-	if (parent)
-		kref_put(&parent->ref, mdev_release_parent);
+	return (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0);
 }
 
-static struct parent_device *mdev_get_parent_from_dev(struct device *dev)
+static struct mdev_device *find_mdev_device(struct mdev_host *host,
+					    uuid_le uuid)
 {
-	struct parent_device *parent;
+	struct device *dev;
 
-	mutex_lock(&parent_list_lock);
-	parent = mdev_get_parent(__find_parent_device(dev));
-	mutex_unlock(&parent_list_lock);
+	dev = device_find_child(&host->dev, &uuid, __find_mdev_device);
+	if (!dev)
+		return NULL;
 
-	return parent;
+	return dev_to_mdev(dev);
 }
 
 static int mdev_device_create_ops(struct mdev_device *mdev, char *mdev_params)
 {
-	struct parent_device *parent = mdev->parent;
-	int ret;
-
-	ret = parent->ops->create(mdev, mdev_params);
-	if (ret)
-		return ret;
-
-	ret = mdev_add_attribute_group(&mdev->dev,
-					parent->ops->mdev_attr_groups);
-	if (ret)
-		parent->ops->destroy(mdev);
+	struct mdev_host *host = dev_to_host(mdev->dev.parent);
 
-	return ret;
+	return host->ops->create(mdev, mdev_params);
 }
 
-static int mdev_device_destroy_ops(struct mdev_device *mdev, bool force)
+static void mdev_device_destroy_ops(struct mdev_device *mdev)
 {
-	struct parent_device *parent = mdev->parent;
-	int ret = 0;
+	struct mdev_host *host = dev_to_host(mdev->dev.parent);
 
-	/*
-	 * If vendor driver doesn't return success that means vendor
-	 * driver doesn't support hot-unplug
-	 */
-	ret = parent->ops->destroy(mdev);
-	if (ret && !force)
-		return -EBUSY;
-
-	mdev_remove_attribute_group(&mdev->dev,
-				    parent->ops->mdev_attr_groups);
-
-	return ret;
-}
-
-static void mdev_release_device(struct kref *kref)
-{
-	struct mdev_device *mdev = container_of(kref, struct mdev_device, ref);
-	struct parent_device *parent = mdev->parent;
-
-	list_del(&mdev->next);
-
-	/*
-	 * This unlock pairs with mutex held by mdev_put_device() through
-	 * kref_put_mutex()
-	 */
-	mutex_unlock(&parent->mdev_list_lock);
-
-	device_unregister(&mdev->dev);
-	wake_up(&parent->release_done);
-	mdev_put_parent(parent);
-}
-
-struct mdev_device *mdev_get_device(struct mdev_device *mdev)
-{
-	if (mdev)
-		kref_get(&mdev->ref);
-	return mdev;
+	host->ops->destroy(mdev);
 }
-EXPORT_SYMBOL(mdev_get_device);
-
-void mdev_put_device(struct mdev_device *mdev)
-{
-	struct parent_device *parent;
-
-	if (!mdev)
-		return;
-
-	parent = mdev->parent;
-	kref_put_mutex(&mdev->ref, mdev_release_device,
-		       &parent->mdev_list_lock);
-}
-EXPORT_SYMBOL(mdev_put_device);
 
 /*
- * mdev_register_device : Register a device
- * @dev: device structure representing parent device.
+ * mdev_register_host_device : register a mdev host device
+ * @dev: device structure of the physical device under which the created
+ *       host device will be.
  * @ops: Parent device operation structure to be registered.
  *
- * Add device to list of registered parent devices.
- * Returns a negative value on error, otherwise 0.
+ * Register a mdev host device as the mediator of mdev devices.
+ * Returns the pointer of mdev host device structure for success, NULL
+ * for errors.
  */
-int mdev_register_device(struct device *dev, const struct parent_ops *ops)
+struct mdev_host *mdev_register_host_device(struct device *pdev,
+				const struct mdev_host_ops *ops)
 {
-	int ret = 0;
-	struct parent_device *parent;
+	int rc = 0;
+	struct mdev_host *host;
 
-	if (!dev || !ops)
-		return -EINVAL;
+	if (!pdev || !ops) {
+		dev_warn(pdev, "dev or ops is NULL\n");
+		return NULL;
+	}
 
 	/* check for mandatory ops */
-	if (!ops->create || !ops->destroy)
-		return -EINVAL;
-
-	mutex_lock(&parent_list_lock);
-
-	/* Check for duplicate */
-	parent = __find_parent_device(dev);
-	if (parent) {
-		ret = -EEXIST;
-		goto add_dev_err;
+	if (!ops->create || !ops->destroy) {
+		dev_warn(pdev, "create and destroy methods are necessary\n");
+		return NULL;
 	}
 
-	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
-	if (!parent) {
-		ret = -ENOMEM;
-		goto add_dev_err;
-	}
+	host = kzalloc(sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return NULL;
 
-	kref_init(&parent->ref);
-	list_add(&parent->next, &parent_list);
+	host->dev.parent = pdev;
+	host->ops = ops;
+	dev_set_name(&host->dev, "mdev-host");
 
-	parent->dev = dev;
-	parent->ops = ops;
-	mutex_init(&parent->mdev_list_lock);
-	INIT_LIST_HEAD(&parent->mdev_list);
-	init_waitqueue_head(&parent->release_done);
-	mutex_unlock(&parent_list_lock);
+	rc = device_register(&host->dev);
+	if (rc)
+		goto register_error;
 
-	ret = parent_create_sysfs_files(dev);
-	if (ret)
+	rc = mdev_create_sysfs_files(&host->dev);
+	if (rc)
 		goto add_sysfs_error;
 
-	ret = mdev_add_attribute_group(dev, ops->dev_attr_groups);
-	if (ret)
+	rc = sysfs_create_groups(&host->dev.kobj, ops->hdev_attr_groups);
+	if (rc)
 		goto add_group_error;
 
-	dev_info(dev, "MDEV: Registered\n");
-	return 0;
+	dev_info(&host->dev, "mdev host device registered\n");
+	return host;
 
 add_group_error:
-	mdev_remove_sysfs_files(dev);
+	mdev_remove_sysfs_files(&host->dev);
+
 add_sysfs_error:
-	mutex_lock(&parent_list_lock);
-	list_del(&parent->next);
-	mutex_unlock(&parent_list_lock);
-	mdev_put_parent(parent);
-	return ret;
+	device_unregister(&host->dev);
 
-add_dev_err:
-	mutex_unlock(&parent_list_lock);
-	return ret;
+register_error:
+	kfree(host);
+	return NULL;
 }
-EXPORT_SYMBOL(mdev_register_device);
-
-/*
- * mdev_unregister_device : Unregister a parent device
- * @dev: device structure representing parent device.
- *
- * Remove device from list of registered parent devices. Give a chance to free
- * existing mediated devices for given device.
- */
+EXPORT_SYMBOL(mdev_register_host_device);
 
-void mdev_unregister_device(struct device *dev)
+static int __mdev_device_destroy(struct device *dev, void *data)
 {
-	struct parent_device *parent;
-	struct mdev_device *mdev = NULL;
-	int ret;
+	struct mdev_device *mdev = dev_to_mdev(dev);
 
-	mutex_lock(&parent_list_lock);
-	parent = __find_parent_device(dev);
-
-	if (!parent) {
-		mutex_unlock(&parent_list_lock);
-		return;
-	}
-	dev_info(dev, "MDEV: Unregistering\n");
-
-	/*
-	 * Remove parent from the list and remove "mdev_create" and
-	 * "mdev_destroy" sysfs files so that no new mediated device could be
-	 * created for this parent
-	 */
-	list_del(&parent->next);
-	parent_remove_sysfs_files(dev);
-	mutex_unlock(&parent_list_lock);
-
-	mdev_remove_attribute_group(dev,
-				    parent->ops->dev_attr_groups);
-
-	while (!list_empty(&parent->mdev_list)) {
-		mutex_lock(&parent->mdev_list_lock);
-		if (!list_empty(&parent->mdev_list)) {
-			mdev = list_first_entry(&parent->mdev_list,
-						struct mdev_device, next);
-			mdev_device_destroy_ops(mdev, true);
-		}
-		mutex_unlock(&parent->mdev_list_lock);
-
-		if (mdev)
-			mdev_put_device(mdev);
-	}
+	mdev_device_destroy_ops(mdev);
+	device_unregister(&mdev->dev);
 
-	do {
-		ret = wait_event_interruptible_timeout(parent->release_done,
-				list_empty(&parent->mdev_list), HZ * 10);
-		if (ret == -ERESTARTSYS) {
-			dev_warn(dev, "Mediated devices are in use, task"
-				      " \"%s\" (%d) "
-				      "blocked until all are released",
-				      current->comm, task_pid_nr(current));
-		}
-	} while (ret <= 0);
-
-	mdev_put_parent(parent);
+	return 0;
 }
-EXPORT_SYMBOL(mdev_unregister_device);
 
 /*
- * Functions required for mdev_sysfs
+ * mdev_unregister_host_device : unregister a mdev host device
+ * @host: the mdev host device structure
+ *
+ * Unregister a mdev host device as the mediator
  */
-static void mdev_device_release(struct device *dev)
+void mdev_unregister_host_device(struct mdev_host *host)
 {
-	struct mdev_device *mdev = to_mdev_device(dev);
+	if (!host)
+		return;
 
-	dev_dbg(&mdev->dev, "MDEV: destroying\n");
-	kfree(mdev);
+	dev_info(&host->dev, "mdev host device unregistered\n");
+
+	mdev_remove_sysfs_files(&host->dev);
+	sysfs_remove_groups(&host->dev.kobj, host->ops->hdev_attr_groups);
+	device_for_each_child(&host->dev, NULL,  __mdev_device_destroy);
+	device_unregister(&host->dev);
 }
+EXPORT_SYMBOL(mdev_unregister_host_device);
 
 int mdev_device_create(struct device *dev, uuid_le uuid, char *mdev_params)
 {
 	int ret;
 	struct mdev_device *mdev;
-	struct parent_device *parent;
-
-	parent = mdev_get_parent_from_dev(dev);
-	if (!parent)
-		return -EINVAL;
+	struct mdev_host *host = dev_to_host(dev);
 
-	mutex_lock(&parent->mdev_list_lock);
 	/* Check for duplicate */
-	mdev = __find_mdev_device(parent, uuid);
+	mdev = find_mdev_device(host, uuid);
 	if (mdev) {
 		ret = -EEXIST;
 		goto create_err;
@@ -345,12 +178,10 @@  int mdev_device_create(struct device *dev, uuid_le uuid, char *mdev_params)
 	}
 
 	memcpy(&mdev->uuid, &uuid, sizeof(uuid_le));
-	mdev->parent = parent;
-	kref_init(&mdev->ref);
 
-	mdev->dev.parent  = dev;
-	mdev->dev.bus     = &mdev_bus_type;
-	mdev->dev.release = mdev_device_release;
+	mdev->dev.parent = dev;
+	mdev->dev.bus = &mdev_bus_type;
+	mdev->dev.groups = host->ops->mdev_attr_groups;
 	dev_set_name(&mdev->dev, "%pUl", uuid.b);
 
 	ret = device_register(&mdev->dev);
@@ -363,123 +194,35 @@  int mdev_device_create(struct device *dev, uuid_le uuid, char *mdev_params)
 	if (ret)
 		goto create_failed;
 
-	ret = mdev_create_sysfs_files(&mdev->dev);
-	if (ret)
-		goto create_sysfs_error;
-
-	list_add(&mdev->next, &parent->mdev_list);
-	mutex_unlock(&parent->mdev_list_lock);
-
 	dev_dbg(&mdev->dev, "MDEV: created\n");
 
 	return ret;
 
-create_sysfs_error:
-	mdev_device_destroy_ops(mdev, true);
-
 create_failed:
 	device_unregister(&mdev->dev);
 
 create_err:
-	mutex_unlock(&parent->mdev_list_lock);
-	mdev_put_parent(parent);
 	return ret;
 }
 
 int mdev_device_destroy(struct device *dev, uuid_le uuid)
 {
 	struct mdev_device *mdev;
-	struct parent_device *parent;
-	int ret;
+	struct mdev_host *host = dev_to_host(dev);
 
-	parent = mdev_get_parent_from_dev(dev);
-	if (!parent)
+	mdev = find_mdev_device(host, uuid);
+	if (!mdev)
 		return -ENODEV;
 
-	mutex_lock(&parent->mdev_list_lock);
-	mdev = __find_mdev_device(parent, uuid);
-	if (!mdev) {
-		ret = -EINVAL;
-		goto destroy_err;
-	}
-
-	mdev_remove_sysfs_files(&mdev->dev);
-	ret = mdev_device_destroy_ops(mdev, false);
-	if (ret)
-		goto destroy_err;
-
-	mutex_unlock(&parent->mdev_list_lock);
-	mdev_put_device(mdev);
-
-	mdev_put_parent(parent);
-	return ret;
-
-destroy_err:
-	mutex_unlock(&parent->mdev_list_lock);
-	mdev_put_parent(parent);
-	return ret;
+	return __mdev_device_destroy(&mdev->dev, NULL);
 }
 
 void mdev_device_supported_config(struct device *dev, char *str)
 {
-	struct parent_device *parent;
-
-	parent = mdev_get_parent_from_dev(dev);
+	struct mdev_host *host = dev_to_host(dev);
 
-	if (parent) {
-		if (parent->ops->supported_config)
-			parent->ops->supported_config(parent->dev, str);
-		mdev_put_parent(parent);
-	}
-}
-
-int mdev_device_set_online_status(struct device *dev, bool online)
-{
-	int ret = 0;
-	struct mdev_device *mdev;
-	struct parent_device *parent;
-
-	mdev = mdev_get_device(to_mdev_device(dev));
-	if (!mdev)
-		return -EINVAL;
-
-	parent = mdev->parent;
-
-	if (parent->ops->set_online_status)
-		ret = parent->ops->set_online_status(mdev, online);
-
-	if (ret)
-		pr_err("mdev online failed  %d\n", ret);
-	else {
-		if (online)
-			kobject_uevent(&mdev->dev.kobj, KOBJ_ONLINE);
-		else
-			kobject_uevent(&mdev->dev.kobj, KOBJ_OFFLINE);
-	}
-
-	mdev_put_device(mdev);
-
-	return ret;
-}
-
-int mdev_device_get_online_status(struct device *dev, bool *online)
-{
-	int ret = 0;
-	struct mdev_device *mdev;
-	struct parent_device *parent;
-
-	mdev = mdev_get_device(to_mdev_device(dev));
-	if (!mdev)
-		return -EINVAL;
-
-	parent = mdev->parent;
-
-	if (parent->ops->get_online_status)
-		ret = parent->ops->get_online_status(mdev, online);
-
-	mdev_put_device(mdev);
-
-	return ret;
+	if (host->ops->supported_config)
+		host->ops->supported_config(&host->dev, str);
 }
 
 static int __init mdev_init(void)
@@ -487,10 +230,8 @@  static int __init mdev_init(void)
 	int ret;
 
 	ret = mdev_bus_register();
-	if (ret) {
-		pr_err("Failed to register mdev bus\n");
-		return ret;
-	}
+	if (ret)
+		pr_err("failed to register mdev bus: %d\n", ret);
 
 	return ret;
 }
diff --git a/drivers/vfio/mdev/mdev_driver.c b/drivers/vfio/mdev/mdev_driver.c
index 8afc2d8..d298aaf 100644
--- a/drivers/vfio/mdev/mdev_driver.c
+++ b/drivers/vfio/mdev/mdev_driver.c
@@ -5,6 +5,8 @@ 
  *     Author: Neo Jia <cjia@nvidia.com>
  *	       Kirti Wankhede <kwankhede@nvidia.com>
  *
+ * Copyright (c) 2016 Intel Corporation.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -52,7 +54,7 @@  static void mdev_detach_iommu(struct mdev_device *mdev)
 static int mdev_probe(struct device *dev)
 {
 	struct mdev_driver *drv = to_mdev_driver(dev->driver);
-	struct mdev_device *mdev = to_mdev_device(dev);
+	struct mdev_device *mdev = dev_to_mdev(dev);
 	int ret;
 
 	ret = mdev_attach_iommu(mdev);
@@ -73,7 +75,7 @@  static int mdev_probe(struct device *dev)
 static int mdev_remove(struct device *dev)
 {
 	struct mdev_driver *drv = to_mdev_driver(dev->driver);
-	struct mdev_device *mdev = to_mdev_device(dev);
+	struct mdev_device *mdev = dev_to_mdev(dev);
 
 	if (drv && drv->remove)
 		drv->remove(dev);
@@ -83,10 +85,32 @@  static int mdev_remove(struct device *dev)
 	return 0;
 }
 
+static int mdev_online(struct device *dev)
+{
+	struct mdev_driver *drv = to_mdev_driver(dev->driver);
+
+	if (drv && drv->online)
+		return drv->online(dev);
+
+	return 0;
+}
+
+static int mdev_offline(struct device *dev)
+{
+	struct mdev_driver *drv = to_mdev_driver(dev->driver);
+
+	if (drv && drv->offline)
+		return drv->offline(dev);
+
+	return 0;
+}
+
 struct bus_type mdev_bus_type = {
 	.name		= "mdev",
 	.probe		= mdev_probe,
 	.remove		= mdev_remove,
+	.online		= mdev_online,
+	.offline	= mdev_offline,
 };
 EXPORT_SYMBOL_GPL(mdev_bus_type);
 
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h
index 07ad1b3..f153292 100644
--- a/drivers/vfio/mdev/mdev_private.h
+++ b/drivers/vfio/mdev/mdev_private.h
@@ -5,6 +5,8 @@ 
  *     Author: Neo Jia <cjia@nvidia.com>
  *	       Kirti Wankhede <kwankhede@nvidia.com>
  *
+ * Copyright (c) 2016 Intel Corporation.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -17,12 +19,6 @@  int  mdev_bus_register(void);
 void mdev_bus_unregister(void);
 
 /* Function prototypes for mdev_sysfs */
-
-extern struct class_attribute mdev_class_attrs[];
-
-int  parent_create_sysfs_files(struct device *dev);
-void parent_remove_sysfs_files(struct device *dev);
-
 int  mdev_create_sysfs_files(struct device *dev);
 void mdev_remove_sysfs_files(struct device *dev);
 
@@ -30,7 +26,4 @@  int  mdev_device_create(struct device *dev, uuid_le uuid, char *mdev_params);
 int  mdev_device_destroy(struct device *dev, uuid_le uuid);
 void mdev_device_supported_config(struct device *dev, char *str);
 
-int mdev_device_set_online_status(struct device *dev, bool online);
-int mdev_device_get_online_status(struct device *dev, bool *online);
-
 #endif /* MDEV_PRIVATE_H */
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c
index ed55cd5..7d55188 100644
--- a/drivers/vfio/mdev/mdev_sysfs.c
+++ b/drivers/vfio/mdev/mdev_sysfs.c
@@ -5,6 +5,10 @@ 
  *     Author: Neo Jia <cjia@nvidia.com>
  *	       Kirti Wankhede <kwankhede@nvidia.com>
  *
+ * Copyright (c) 2016 Intel Corporation.
+ * Author:
+ *	Jike Song <jike.song@intel.com>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -35,17 +39,17 @@  static ssize_t mdev_destroy_store(struct device *dev,
 				  const char *buf, size_t count);
 static DEVICE_ATTR_WO(mdev_destroy);
 
-static ssize_t online_store(struct device *dev, struct device_attribute *attr,
-			    const char *buf, size_t count);
-static ssize_t online_show(struct device *dev, struct device_attribute *attr,
-			   char *buf);
-static DEVICE_ATTR_RW(online);
+static const struct attribute *mdev_host_attrs[] = {
+	&dev_attr_mdev_supported_types.attr,
+	&dev_attr_mdev_create.attr,
+	&dev_attr_mdev_destroy.attr,
+	NULL,
+};
 
-/* Static functions */
 
 #define SUPPORTED_TYPE_BUFFER_LENGTH	4096
 
-/* mdev sysfs Functions */
+/* mdev host sysfs functions */
 static ssize_t mdev_supported_types_show(struct device *dev,
 					 struct device_attribute *attr,
 					 char *buf)
@@ -70,25 +74,24 @@  static ssize_t mdev_create_store(struct device *dev,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
 {
-	char *str, *pstr;
-	char *uuid_str, *mdev_params = NULL, *params = NULL;
+	char *str;
+	char *uuid_str, *params = NULL;
 	uuid_le uuid;
 	int ret;
 
-	pstr = str = kstrndup(buf, count, GFP_KERNEL);
-
+	str = kstrndup(buf, count, GFP_KERNEL);
 	if (!str)
 		return -ENOMEM;
 
 	uuid_str = strsep(&str, ":");
 	if (!uuid_str) {
-		pr_err("mdev_create: Empty UUID string %s\n", buf);
+		pr_err("mdev_create: empty UUID string %s\n", buf);
 		ret = -EINVAL;
 		goto create_error;
 	}
 
 	if (str)
-		params = mdev_params = kstrdup(str, GFP_KERNEL);
+		params = kstrdup(str, GFP_KERNEL);
 
 	ret = uuid_le_to_bin(uuid_str, &uuid);
 	if (ret) {
@@ -96,7 +99,7 @@  static ssize_t mdev_create_store(struct device *dev,
 		goto create_error;
 	}
 
-	ret = mdev_device_create(dev, uuid, mdev_params);
+	ret = mdev_device_create(dev, uuid, params);
 	if (ret)
 		pr_err("mdev_create: Failed to create mdev device\n");
 	else
@@ -104,7 +107,7 @@  static ssize_t mdev_create_store(struct device *dev,
 
 create_error:
 	kfree(params);
-	kfree(pstr);
+	kfree(str);
 	return ret;
 }
 
@@ -112,23 +115,15 @@  static ssize_t mdev_destroy_store(struct device *dev,
 				  struct device_attribute *attr,
 				  const char *buf, size_t count)
 {
-	char *uuid_str, *str, *pstr;
+	char *str;
 	uuid_le uuid;
 	int ret;
 
-	str = pstr = kstrndup(buf, count, GFP_KERNEL);
-
+	str = kstrndup(buf, count, GFP_KERNEL);
 	if (!str)
 		return -ENOMEM;
 
-	uuid_str = strsep(&str, ":");
-	if (!uuid_str) {
-		pr_err("mdev_destroy: Empty UUID string %s\n", buf);
-		ret = -EINVAL;
-		goto destroy_error;
-	}
-
-	ret = uuid_le_to_bin(uuid_str, &uuid);
+	ret = uuid_le_to_bin(str, &uuid);
 	if (ret) {
 		pr_err("mdev_destroy: UUID parse error  %s\n", buf);
 		goto destroy_error;
@@ -139,102 +134,22 @@  static ssize_t mdev_destroy_store(struct device *dev,
 		ret = count;
 
 destroy_error:
-	kfree(pstr);
-	return ret;
-}
-
-static ssize_t online_store(struct device *dev, struct device_attribute *attr,
-			    const char *buf, size_t count)
-{
-	char *str;
-	int ret;
-	uint32_t online_status;
-	bool online;
-
-	str = kstrndup(buf, count, GFP_KERNEL);
-	if (!str)
-		return -ENOMEM;
-
-	ret = kstrtouint(str, 0, &online_status);
 	kfree(str);
-
-	if (ret) {
-		pr_err("online: parsing error %s\n", buf);
-		return ret;
-	}
-
-	online = online_status > 0 ? true : false;
-
-	ret = mdev_device_set_online_status(dev, online);
-	if (ret)
-		return ret;
-
-	return count;
-}
-
-static ssize_t online_show(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	int ret;
-	bool online = false;
-
-	ret = mdev_device_get_online_status(dev, &online);
-	if (ret)
-		return ret;
-
-	ret = sprintf(buf, "%d\n", online);
 	return ret;
 }
 
-int parent_create_sysfs_files(struct device *dev)
-{
-	int ret;
-
-	ret = sysfs_create_file(&dev->kobj,
-				&dev_attr_mdev_supported_types.attr);
-	if (ret) {
-		pr_err("Failed to create mdev_supported_types sysfs entry\n");
-		return ret;
-	}
-
-	ret = sysfs_create_file(&dev->kobj, &dev_attr_mdev_create.attr);
-	if (ret) {
-		pr_err("Failed to create mdev_create sysfs entry\n");
-		goto create_sysfs_failed;
-	}
-
-	ret = sysfs_create_file(&dev->kobj, &dev_attr_mdev_destroy.attr);
-	if (ret) {
-		pr_err("Failed to create mdev_destroy sysfs entry\n");
-		sysfs_remove_file(&dev->kobj, &dev_attr_mdev_create.attr);
-	} else
-		return ret;
-
-create_sysfs_failed:
-	sysfs_remove_file(&dev->kobj, &dev_attr_mdev_supported_types.attr);
-	return ret;
-}
-
-void parent_remove_sysfs_files(struct device *dev)
-{
-	sysfs_remove_file(&dev->kobj, &dev_attr_mdev_supported_types.attr);
-	sysfs_remove_file(&dev->kobj, &dev_attr_mdev_create.attr);
-	sysfs_remove_file(&dev->kobj, &dev_attr_mdev_destroy.attr);
-}
-
 int mdev_create_sysfs_files(struct device *dev)
 {
 	int ret;
 
-	ret = sysfs_create_file(&dev->kobj, &dev_attr_online.attr);
+	ret = sysfs_create_files(&dev->kobj, mdev_host_attrs);
 	if (ret)
-		pr_err("Failed to create 'online' entry\n");
+		pr_err("sysfs_create_files failed: %d\n", ret);
 
 	return ret;
 }
 
 void mdev_remove_sysfs_files(struct device *dev)
 {
-	sysfs_remove_file(&dev->kobj, &dev_attr_online.attr);
+	sysfs_remove_files(&dev->kobj, mdev_host_attrs);
 }
-
diff --git a/include/linux/mdev.h b/include/linux/mdev.h
index babcb72..1236200 100644
--- a/include/linux/mdev.h
+++ b/include/linux/mdev.h
@@ -5,6 +5,8 @@ 
  *     Author: Neo Jia <cjia@nvidia.com>
  *	       Kirti Wankhede <kwankhede@nvidia.com>
  *
+ * Copyright (c) 2016 Intel Corporation.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -15,65 +17,50 @@ 
 
 #include <uapi/linux/vfio.h>
 
-struct parent_device;
-
-/*
- * Mediated device
- */
 
+/* mediated device */
 struct mdev_device {
 	struct device		dev;
-	struct parent_device	*parent;
 	struct iommu_group	*group;
 	uuid_le			uuid;
 	void			*driver_data;
-
-	/* internal only */
-	struct kref		ref;
-	struct list_head	next;
 };
 
-
 /**
- * struct parent_ops - Structure to be registered for each parent device to
- * register the device to mdev module.
+ * struct mdev_host_ops - Structure to be registered for each host device to
+ * to mdev.
  *
  * @owner:		The module owner.
- * @dev_attr_groups:	Default attributes of the parent device.
- * @mdev_attr_groups:	Default attributes of the mediated device.
+ * @hdev_attr_groups:	Default attributes of the host device.
+ * @mdev_attr_groups:	Default attributes of the mdev device.
  * @supported_config:	Called to get information about supported types.
- *			@dev : device structure of parent device.
+ *			@dev : device structure of host device.
  *			@config: should return string listing supported config
  *			Returns integer: success (0) or error (< 0)
- * @create:		Called to allocate basic resources in parent device's
+ * @create:		Called to allocate basic resources in host device's
  *			driver for a particular mediated device. It is
  *			mandatory to provide create ops.
  *			@mdev: mdev_device structure on of mediated device
  *			      that is being created
- *			@mdev_params: extra parameters required by parent
+ *			@mdev_params: extra parameters required by host
  *			device's driver.
  *			Returns integer: success (0) or error (< 0)
- * @destroy:		Called to free resources in parent device's driver for a
- *			a mediated device. It is mandatory to provide destroy
- *			ops.
+ * @destroy:		Called to free resources in host device's driver for a
+ *			a mediated device instance. It is mandatory to provide
+ *			destroy ops.
  *			@mdev: mdev_device device structure which is being
- *			       destroyed
+ *				destroyed
  *			Returns integer: success (0) or error (< 0)
  *			If VMM is running and destroy() is called that means the
  *			mdev is being hotunpluged. Return error if VMM is
  *			running and driver doesn't support mediated device
  *			hotplug.
- * @reset:		Called to reset mediated device.
- *			@mdev: mdev_device device structure.
- *			Returns integer: success (0) or error (< 0)
- * @set_online_status:	Called to change to status of mediated device.
- *			@mdev: mediated device.
- *			@online: set true or false to make mdev device online or
- *			offline.
+ * @start:		Called to initiate mediated device initialization
+ *			process in host device's driver before VMM starts.
+ *			@mdev: mediated device structure
  *			Returns integer: success (0) or error (< 0)
- * @get_online_status:	Called to get online/offline status of  mediated device
- *			@mdev: mediated device.
- *			@online: Returns status of mediated device.
+ * @stop:		Called to teardown mediated device related resources
+ *			@mdev: mediated device structure
  *			Returns integer: success (0) or error (< 0)
  * @read:		Read emulation callback
  *			@mdev: mediated device structure
@@ -87,75 +74,47 @@  struct mdev_device {
  *			@count: number of bytes to be written
  *			@pos: address.
  *			Retuns number on bytes written on success or error.
- * @get_irq_info:	Called to retrieve information about mediated device IRQ
- *			@mdev: mediated device structure
- *			@irq_info: VFIO IRQ flags and count.
- *			Returns integer: success (0) or error (< 0)
- * @set_irqs:		Called to send about interrupts configuration
- *			information that VMM sets.
+ * @mmap:		Memory Map
  *			@mdev: mediated device structure
- *			@flags, index, start, count and *data : same as that of
- *			struct vfio_irq_set of VFIO_DEVICE_SET_IRQS API.
- * @get_device_info:	Called to get VFIO device information for a mediated
- *			device.
- *			@vfio_device_info: VFIO device info.
- *			Returns integer: success (0) or error (< 0)
- * @get_region_info:	Called to get VFIO region size and flags of mediated
- *			device.
- *			@mdev: mediated device structure
- *			@region_info: output, returns size and flags of
- *				      requested region.
- *			@cap_type_id: returns id of capability.
- *			@cap_type: returns pointer to capability structure
- *			corresponding to capability id.
+ *			@pos: address
+ *			@virtaddr: target user address to start at. Vendor
+ *			driver can change if required.
+ *			@pfn: host address of kernel memory, vendor driver
+ *			can change if required.
+ *			@size: size of map area, vendor driver can change the
+ *			size of map area if desired.
+ *			@prot: page protection flags for this mapping, vendor
+ *			driver can change, if required.
  *			Returns integer: success (0) or error (< 0)
  *
- * Parent device that support mediated device should be registered with mdev
- * module with parent_ops structure.
+ * Host device that support mediated device should be registered with mdev
+ * module with mdev_host_ops structure.
  */
-
-struct parent_ops {
-	struct module   *owner;
-	const struct attribute_group **dev_attr_groups;
+struct mdev_host_ops {
+	struct module *owner;
+	const struct attribute_group **hdev_attr_groups;
 	const struct attribute_group **mdev_attr_groups;
 
-	int	(*supported_config)(struct device *dev, char *config);
-	int     (*create)(struct mdev_device *mdev, char *mdev_params);
-	int     (*destroy)(struct mdev_device *mdev);
-	int     (*reset)(struct mdev_device *mdev);
-	int     (*set_online_status)(struct mdev_device *mdev, bool online);
-	int     (*get_online_status)(struct mdev_device *mdev, bool *online);
-	ssize_t (*read)(struct mdev_device *mdev, char *buf, size_t count,
-			loff_t pos);
-	ssize_t (*write)(struct mdev_device *mdev, char *buf, size_t count,
-			 loff_t pos);
-	int	(*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma);
-	int	(*get_irq_info)(struct mdev_device *mdev,
-				struct vfio_irq_info *irq_info);
-	int     (*set_irqs)(struct mdev_device *mdev, uint32_t flags,
-			    unsigned int index, unsigned int start,
-			    unsigned int count, void *data);
-	int	(*get_device_info)(struct mdev_device *mdev,
-				   struct vfio_device_info *dev_info);
-	int	(*get_region_info)(struct mdev_device *mdev,
-				   struct vfio_region_info *region_info,
-				   u16 *cap_type_id, void **cap_type);
-};
+	int (*supported_config)(struct device *dev, char *config);
+	int (*create)(struct mdev_device *mdev, char *mdev_params);
+	void (*destroy)(struct mdev_device *mdev);
 
-/*
- * Parent Device
- */
+	int (*start)(struct mdev_device *mdev);
+	int (*stop)(struct mdev_device *mdev);
 
-struct parent_device {
-	struct device		*dev;
-	const struct parent_ops	*ops;
+	ssize_t (*read)(struct mdev_device *mdev, char __user *buf,
+			size_t count, loff_t *pos);
+	ssize_t (*write)(struct mdev_device *mdev, const char __user *buf,
+			size_t count, loff_t *pos);
+	int (*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma);
+	long (*ioctl)(struct mdev_device *mdev, unsigned int cmd,
+			unsigned long arg);
+};
 
-	/* internal */
-	struct kref		ref;
-	struct list_head	next;
-	struct list_head	mdev_list;
-	struct mutex		mdev_list_lock;
-	wait_queue_head_t	release_done;
+/* mdev host device */
+struct mdev_host {
+	struct device dev;
+	const struct mdev_host_ops *ops;
 };
 
 /**
@@ -164,25 +123,16 @@  struct parent_device {
  * @probe: called when new device created
  * @remove: called when device removed
  * @driver: device driver structure
- *
  **/
 struct mdev_driver {
 	const char *name;
-	int  (*probe)(struct device *dev);
+	int (*probe)(struct device *dev);
 	void (*remove)(struct device *dev);
+	int (*online)(struct device *dev);
+	int (*offline)(struct device *dev);
 	struct device_driver driver;
 };
 
-static inline struct mdev_driver *to_mdev_driver(struct device_driver *drv)
-{
-	return drv ? container_of(drv, struct mdev_driver, driver) : NULL;
-}
-
-static inline struct mdev_device *to_mdev_device(struct device *dev)
-{
-	return dev ? container_of(dev, struct mdev_device, dev) : NULL;
-}
-
 static inline void *mdev_get_drvdata(struct mdev_device *mdev)
 {
 	return mdev->driver_data;
@@ -195,18 +145,15 @@  static inline void mdev_set_drvdata(struct mdev_device *mdev, void *data)
 
 extern struct bus_type mdev_bus_type;
 
-#define dev_is_mdev(d) ((d)->bus == &mdev_bus_type)
-
-extern int  mdev_register_device(struct device *dev,
-				 const struct parent_ops *ops);
-extern void mdev_unregister_device(struct device *dev);
-
-extern int  mdev_register_driver(struct mdev_driver *drv, struct module *owner);
-extern void mdev_unregister_driver(struct mdev_driver *drv);
+#define to_mdev_driver(drv) container_of(drv, struct mdev_driver, driver)
+#define dev_to_host(_dev) container_of((_dev), struct mdev_host, dev)
+#define dev_to_mdev(_dev) container_of((_dev), struct mdev_device, dev)
 
-extern struct mdev_device *mdev_get_device(struct mdev_device *mdev);
-extern void mdev_put_device(struct mdev_device *mdev);
+struct mdev_host *mdev_register_host_device(struct device *dev,
+				 const struct mdev_host_ops *ops);
+void mdev_unregister_host_device(struct mdev_host *host);
 
-extern struct mdev_device *mdev_get_device_by_group(struct iommu_group *group);
+int mdev_register_driver(struct mdev_driver *drv, struct module *owner);
+void mdev_unregister_driver(struct mdev_driver *drv);
 
 #endif /* MDEV_H */