@@ -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/
@@ -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.
-
@@ -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
@@ -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;
}
@@ -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);
@@ -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 */
@@ -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);
}
-
@@ -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 */