aboutsummaryrefslogtreecommitdiffstats
path: root/samples/vfio-mdev
diff options
context:
space:
mode:
Diffstat (limited to 'samples/vfio-mdev')
-rw-r--r--samples/vfio-mdev/mbochs.c345
-rw-r--r--samples/vfio-mdev/mdpy-defs.h2
-rw-r--r--samples/vfio-mdev/mdpy-fb.c13
-rw-r--r--samples/vfio-mdev/mdpy.c343
-rw-r--r--samples/vfio-mdev/mtty.c397
5 files changed, 465 insertions, 635 deletions
diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c
index 3cc5e5921682..117a8d799f71 100644
--- a/samples/vfio-mdev/mbochs.c
+++ b/samples/vfio-mdev/mbochs.c
@@ -21,7 +21,6 @@
*/
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -100,36 +99,46 @@ MODULE_PARM_DESC(mem, "megabytes available to " MBOCHS_NAME " devices");
#define MBOCHS_TYPE_2 "medium"
#define MBOCHS_TYPE_3 "large"
-static const struct mbochs_type {
- const char *name;
+static struct mbochs_type {
+ struct mdev_type type;
u32 mbytes;
u32 max_x;
u32 max_y;
} mbochs_types[] = {
{
- .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1,
+ .type.sysfs_name = MBOCHS_TYPE_1,
+ .type.pretty_name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1,
.mbytes = 4,
.max_x = 800,
.max_y = 600,
}, {
- .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2,
+ .type.sysfs_name = MBOCHS_TYPE_2,
+ .type.pretty_name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2,
.mbytes = 16,
.max_x = 1920,
.max_y = 1440,
}, {
- .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3,
+ .type.sysfs_name = MBOCHS_TYPE_3,
+ .type.pretty_name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3,
.mbytes = 64,
.max_x = 0,
.max_y = 0,
},
};
+static struct mdev_type *mbochs_mdev_types[] = {
+ &mbochs_types[0].type,
+ &mbochs_types[1].type,
+ &mbochs_types[2].type,
+};
static dev_t mbochs_devt;
static struct class *mbochs_class;
static struct cdev mbochs_cdev;
static struct device mbochs_dev;
-static int mbochs_used_mbytes;
+static struct mdev_parent mbochs_parent;
+static atomic_t mbochs_avail_mbytes;
+static const struct vfio_device_ops mbochs_dev_ops;
struct vfio_region_info_ext {
struct vfio_region_info base;
@@ -160,6 +169,7 @@ struct mbochs_dmabuf {
/* State of each mdev device */
struct mdev_state {
+ struct vfio_device vdev;
u8 *vconfig;
u64 bar_mask[3];
u32 memory_bar_mask;
@@ -205,16 +215,6 @@ static struct page *__mbochs_get_page(struct mdev_state *mdev_state,
static struct page *mbochs_get_page(struct mdev_state *mdev_state,
pgoff_t pgoff);
-static const struct mbochs_type *mbochs_find_type(struct kobject *kobj)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mbochs_types); i++)
- if (strcmp(mbochs_types[i].name, kobj->name) == 0)
- return mbochs_types + i;
- return NULL;
-}
-
static void mbochs_create_config_space(struct mdev_state *mdev_state)
{
STORE_LE16((u16 *) &mdev_state->vconfig[PCI_VENDOR_ID],
@@ -435,11 +435,9 @@ static void handle_edid_blob(struct mdev_state *mdev_state, u16 offset,
memcpy(buf, mdev_state->edid_blob + offset, count);
}
-static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count,
- loff_t pos, bool is_write)
+static ssize_t mdev_access(struct mdev_state *mdev_state, char *buf,
+ size_t count, loff_t pos, bool is_write)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
- struct device *dev = mdev_dev(mdev);
struct page *pg;
loff_t poff;
char *map;
@@ -488,7 +486,7 @@ static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count,
put_page(pg);
} else {
- dev_dbg(dev, "%s: %s @0x%llx (unhandled)\n",
+ dev_dbg(mdev_state->vdev.dev, "%s: %s @0x%llx (unhandled)\n",
__func__, is_write ? "WR" : "RD", pos);
ret = -1;
goto accessfailed;
@@ -503,9 +501,8 @@ accessfailed:
return ret;
}
-static int mbochs_reset(struct mdev_device *mdev)
+static int mbochs_reset(struct mdev_state *mdev_state)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
u32 size64k = mdev_state->memsize / (64 * 1024);
int i;
@@ -516,24 +513,25 @@ static int mbochs_reset(struct mdev_device *mdev)
return 0;
}
-static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev)
+static int mbochs_init_dev(struct vfio_device *vdev)
{
- const struct mbochs_type *type = mbochs_find_type(kobj);
- struct device *dev = mdev_dev(mdev);
- struct mdev_state *mdev_state;
-
- if (!type)
- type = &mbochs_types[0];
- if (type->mbytes + mbochs_used_mbytes > max_mbytes)
- return -ENOMEM;
-
- mdev_state = kzalloc(sizeof(struct mdev_state), GFP_KERNEL);
- if (mdev_state == NULL)
- return -ENOMEM;
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
+ struct mdev_device *mdev = to_mdev_device(vdev->dev);
+ struct mbochs_type *type =
+ container_of(mdev->type, struct mbochs_type, type);
+ int avail_mbytes = atomic_read(&mbochs_avail_mbytes);
+ int ret = -ENOMEM;
+
+ do {
+ if (avail_mbytes < type->mbytes)
+ return -ENOSPC;
+ } while (!atomic_try_cmpxchg(&mbochs_avail_mbytes, &avail_mbytes,
+ avail_mbytes - type->mbytes));
mdev_state->vconfig = kzalloc(MBOCHS_CONFIG_SPACE_SIZE, GFP_KERNEL);
- if (mdev_state->vconfig == NULL)
- goto err_mem;
+ if (!mdev_state->vconfig)
+ goto err_avail;
mdev_state->memsize = type->mbytes * 1024 * 1024;
mdev_state->pagecount = mdev_state->memsize >> PAGE_SHIFT;
@@ -541,14 +539,10 @@ static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev)
sizeof(struct page *),
GFP_KERNEL);
if (!mdev_state->pages)
- goto err_mem;
-
- dev_info(dev, "%s: %s, %d MB, %ld pages\n", __func__,
- kobj->name, type->mbytes, mdev_state->pagecount);
+ goto err_vconfig;
mutex_init(&mdev_state->ops_lock);
mdev_state->mdev = mdev;
- mdev_set_drvdata(mdev, mdev_state);
INIT_LIST_HEAD(&mdev_state->dmabufs);
mdev_state->next_id = 1;
@@ -558,32 +552,64 @@ static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev)
mdev_state->edid_regs.edid_offset = MBOCHS_EDID_BLOB_OFFSET;
mdev_state->edid_regs.edid_max_size = sizeof(mdev_state->edid_blob);
mbochs_create_config_space(mdev_state);
- mbochs_reset(mdev);
+ mbochs_reset(mdev_state);
- mbochs_used_mbytes += type->mbytes;
+ dev_info(vdev->dev, "%s: %s, %d MB, %ld pages\n", __func__,
+ type->type.pretty_name, type->mbytes, mdev_state->pagecount);
return 0;
-err_mem:
+err_vconfig:
kfree(mdev_state->vconfig);
- kfree(mdev_state);
- return -ENOMEM;
+err_avail:
+ atomic_add(type->mbytes, &mbochs_avail_mbytes);
+ return ret;
}
-static int mbochs_remove(struct mdev_device *mdev)
+static int mbochs_probe(struct mdev_device *mdev)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
+ struct mdev_state *mdev_state;
+ int ret = -ENOMEM;
+
+ mdev_state = vfio_alloc_device(mdev_state, vdev, &mdev->dev,
+ &mbochs_dev_ops);
+ if (IS_ERR(mdev_state))
+ return PTR_ERR(mdev_state);
- mbochs_used_mbytes -= mdev_state->type->mbytes;
- mdev_set_drvdata(mdev, NULL);
+ ret = vfio_register_emulated_iommu_dev(&mdev_state->vdev);
+ if (ret)
+ goto err_put_vdev;
+ dev_set_drvdata(&mdev->dev, mdev_state);
+ return 0;
+
+err_put_vdev:
+ vfio_put_device(&mdev_state->vdev);
+ return ret;
+}
+
+static void mbochs_release_dev(struct vfio_device *vdev)
+{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
+
+ atomic_add(mdev_state->type->mbytes, &mbochs_avail_mbytes);
kfree(mdev_state->pages);
kfree(mdev_state->vconfig);
- kfree(mdev_state);
- return 0;
+ vfio_free_device(vdev);
}
-static ssize_t mbochs_read(struct mdev_device *mdev, char __user *buf,
+static void mbochs_remove(struct mdev_device *mdev)
+{
+ struct mdev_state *mdev_state = dev_get_drvdata(&mdev->dev);
+
+ vfio_unregister_group_dev(&mdev_state->vdev);
+ vfio_put_device(&mdev_state->vdev);
+}
+
+static ssize_t mbochs_read(struct vfio_device *vdev, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
unsigned int done = 0;
int ret;
@@ -593,7 +619,7 @@ static ssize_t mbochs_read(struct mdev_device *mdev, char __user *buf,
if (count >= 4 && !(*ppos % 4)) {
u32 val;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -605,7 +631,7 @@ static ssize_t mbochs_read(struct mdev_device *mdev, char __user *buf,
} else if (count >= 2 && !(*ppos % 2)) {
u16 val;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -617,7 +643,7 @@ static ssize_t mbochs_read(struct mdev_device *mdev, char __user *buf,
} else {
u8 val;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -640,9 +666,11 @@ read_err:
return -EFAULT;
}
-static ssize_t mbochs_write(struct mdev_device *mdev, const char __user *buf,
+static ssize_t mbochs_write(struct vfio_device *vdev, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
unsigned int done = 0;
int ret;
@@ -655,7 +683,7 @@ static ssize_t mbochs_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -667,7 +695,7 @@ static ssize_t mbochs_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -679,7 +707,7 @@ static ssize_t mbochs_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -765,9 +793,10 @@ static const struct vm_operations_struct mbochs_region_vm_ops = {
.fault = mbochs_region_vm_fault,
};
-static int mbochs_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
+static int mbochs_mmap(struct vfio_device *vdev, struct vm_area_struct *vma)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
if (vma->vm_pgoff != MBOCHS_MEMORY_BAR_OFFSET >> PAGE_SHIFT)
return -EINVAL;
@@ -846,7 +875,7 @@ static struct sg_table *mbochs_map_dmabuf(struct dma_buf_attachment *at,
if (sg_alloc_table_from_pages(sg, dmabuf->pages, dmabuf->pagecount,
0, dmabuf->mode.size, GFP_KERNEL) < 0)
goto err2;
- if (!dma_map_sg(at->dev, sg->sgl, sg->nents, direction))
+ if (dma_map_sgtable(at->dev, sg, direction, 0))
goto err3;
return sg;
@@ -868,6 +897,7 @@ static void mbochs_unmap_dmabuf(struct dma_buf_attachment *at,
dev_dbg(dev, "%s: %d\n", __func__, dmabuf->id);
+ dma_unmap_sgtable(at->dev, sg, direction, 0);
sg_free_table(sg);
kfree(sg);
}
@@ -973,7 +1003,7 @@ mbochs_dmabuf_find_by_id(struct mdev_state *mdev_state, u32 id)
static int mbochs_dmabuf_export(struct mbochs_dmabuf *dmabuf)
{
struct mdev_state *mdev_state = dmabuf->mdev_state;
- struct device *dev = mdev_dev(mdev_state->mdev);
+ struct device *dev = mdev_state->vdev.dev;
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct dma_buf *buf;
@@ -1001,15 +1031,10 @@ static int mbochs_dmabuf_export(struct mbochs_dmabuf *dmabuf)
return 0;
}
-static int mbochs_get_region_info(struct mdev_device *mdev,
+static int mbochs_get_region_info(struct mdev_state *mdev_state,
struct vfio_region_info_ext *ext)
{
struct vfio_region_info *region_info = &ext->base;
- struct mdev_state *mdev_state;
-
- mdev_state = mdev_get_drvdata(mdev);
- if (!mdev_state)
- return -EINVAL;
if (region_info->index >= MBOCHS_NUM_REGIONS)
return -EINVAL;
@@ -1057,15 +1082,13 @@ static int mbochs_get_region_info(struct mdev_device *mdev,
return 0;
}
-static int mbochs_get_irq_info(struct mdev_device *mdev,
- struct vfio_irq_info *irq_info)
+static int mbochs_get_irq_info(struct vfio_irq_info *irq_info)
{
irq_info->count = 0;
return 0;
}
-static int mbochs_get_device_info(struct mdev_device *mdev,
- struct vfio_device_info *dev_info)
+static int mbochs_get_device_info(struct vfio_device_info *dev_info)
{
dev_info->flags = VFIO_DEVICE_FLAGS_PCI;
dev_info->num_regions = MBOCHS_NUM_REGIONS;
@@ -1073,11 +1096,9 @@ static int mbochs_get_device_info(struct mdev_device *mdev,
return 0;
}
-static int mbochs_query_gfx_plane(struct mdev_device *mdev,
+static int mbochs_query_gfx_plane(struct mdev_state *mdev_state,
struct vfio_device_gfx_plane_info *plane)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
- struct device *dev = mdev_dev(mdev);
struct mbochs_dmabuf *dmabuf;
struct mbochs_mode mode;
int ret;
@@ -1131,18 +1152,16 @@ static int mbochs_query_gfx_plane(struct mdev_device *mdev,
done:
if (plane->drm_plane_type == DRM_PLANE_TYPE_PRIMARY &&
mdev_state->active_id != plane->dmabuf_id) {
- dev_dbg(dev, "%s: primary: %d => %d\n", __func__,
- mdev_state->active_id, plane->dmabuf_id);
+ dev_dbg(mdev_state->vdev.dev, "%s: primary: %d => %d\n",
+ __func__, mdev_state->active_id, plane->dmabuf_id);
mdev_state->active_id = plane->dmabuf_id;
}
mutex_unlock(&mdev_state->ops_lock);
return 0;
}
-static int mbochs_get_gfx_dmabuf(struct mdev_device *mdev,
- u32 id)
+static int mbochs_get_gfx_dmabuf(struct mdev_state *mdev_state, u32 id)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
struct mbochs_dmabuf *dmabuf;
mutex_lock(&mdev_state->ops_lock);
@@ -1164,9 +1183,11 @@ static int mbochs_get_gfx_dmabuf(struct mdev_device *mdev,
return dma_buf_fd(dmabuf->buf, 0);
}
-static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
- unsigned long arg)
+static long mbochs_ioctl(struct vfio_device *vdev, unsigned int cmd,
+ unsigned long arg)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
int ret = 0;
unsigned long minsz, outsz;
@@ -1183,7 +1204,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (info.argsz < minsz)
return -EINVAL;
- ret = mbochs_get_device_info(mdev, &info);
+ ret = mbochs_get_device_info(&info);
if (ret)
return ret;
@@ -1207,7 +1228,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (outsz > sizeof(info))
return -EINVAL;
- ret = mbochs_get_region_info(mdev, &info);
+ ret = mbochs_get_region_info(mdev_state, &info);
if (ret)
return ret;
@@ -1230,7 +1251,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
(info.index >= VFIO_PCI_NUM_IRQS))
return -EINVAL;
- ret = mbochs_get_irq_info(mdev, &info);
+ ret = mbochs_get_irq_info(&info);
if (ret)
return ret;
@@ -1253,7 +1274,7 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (plane.argsz < minsz)
return -EINVAL;
- ret = mbochs_query_gfx_plane(mdev, &plane);
+ ret = mbochs_query_gfx_plane(mdev_state, &plane);
if (ret)
return ret;
@@ -1270,29 +1291,22 @@ static long mbochs_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (get_user(dmabuf_id, (__u32 __user *)arg))
return -EFAULT;
- return mbochs_get_gfx_dmabuf(mdev, dmabuf_id);
+ return mbochs_get_gfx_dmabuf(mdev_state, dmabuf_id);
}
case VFIO_DEVICE_SET_IRQS:
return -EINVAL;
case VFIO_DEVICE_RESET:
- return mbochs_reset(mdev);
+ return mbochs_reset(mdev_state);
}
return -ENOTTY;
}
-static int mbochs_open(struct mdev_device *mdev)
-{
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
- return 0;
-}
-
-static void mbochs_close(struct mdev_device *mdev)
+static void mbochs_close_device(struct vfio_device *vdev)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
struct mbochs_dmabuf *dmabuf, *tmp;
mutex_lock(&mdev_state->ops_lock);
@@ -1309,15 +1323,13 @@ static void mbochs_close(struct mdev_device *mdev)
mbochs_put_pages(mdev_state);
mutex_unlock(&mdev_state->ops_lock);
- module_put(THIS_MODULE);
}
static ssize_t
memory_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct mdev_device *mdev = mdev_from_dev(dev);
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
+ struct mdev_state *mdev_state = dev_get_drvdata(dev);
return sprintf(buf, "%d MB\n", mdev_state->type->mbytes);
}
@@ -1333,87 +1345,50 @@ static const struct attribute_group mdev_dev_group = {
.attrs = mdev_dev_attrs,
};
-const struct attribute_group *mdev_dev_groups[] = {
+static const struct attribute_group *mdev_dev_groups[] = {
&mdev_dev_group,
NULL,
};
-static ssize_t
-name_show(struct kobject *kobj, struct device *dev, char *buf)
+static ssize_t mbochs_show_description(struct mdev_type *mtype, char *buf)
{
- return sprintf(buf, "%s\n", kobj->name);
-}
-MDEV_TYPE_ATTR_RO(name);
-
-static ssize_t
-description_show(struct kobject *kobj, struct device *dev, char *buf)
-{
- const struct mbochs_type *type = mbochs_find_type(kobj);
+ struct mbochs_type *type =
+ container_of(mtype, struct mbochs_type, type);
return sprintf(buf, "virtual display, %d MB video memory\n",
type ? type->mbytes : 0);
}
-MDEV_TYPE_ATTR_RO(description);
-static ssize_t
-available_instances_show(struct kobject *kobj, struct device *dev, char *buf)
+static unsigned int mbochs_get_available(struct mdev_type *mtype)
{
- const struct mbochs_type *type = mbochs_find_type(kobj);
- int count = (max_mbytes - mbochs_used_mbytes) / type->mbytes;
-
- return sprintf(buf, "%d\n", count);
-}
-MDEV_TYPE_ATTR_RO(available_instances);
+ struct mbochs_type *type =
+ container_of(mtype, struct mbochs_type, type);
-static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
- char *buf)
-{
- return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
+ return atomic_read(&mbochs_avail_mbytes) / type->mbytes;
}
-MDEV_TYPE_ATTR_RO(device_api);
-
-static struct attribute *mdev_types_attrs[] = {
- &mdev_type_attr_name.attr,
- &mdev_type_attr_description.attr,
- &mdev_type_attr_device_api.attr,
- &mdev_type_attr_available_instances.attr,
- NULL,
-};
-
-static struct attribute_group mdev_type_group1 = {
- .name = MBOCHS_TYPE_1,
- .attrs = mdev_types_attrs,
-};
-
-static struct attribute_group mdev_type_group2 = {
- .name = MBOCHS_TYPE_2,
- .attrs = mdev_types_attrs,
-};
-static struct attribute_group mdev_type_group3 = {
- .name = MBOCHS_TYPE_3,
- .attrs = mdev_types_attrs,
+static const struct vfio_device_ops mbochs_dev_ops = {
+ .close_device = mbochs_close_device,
+ .init = mbochs_init_dev,
+ .release = mbochs_release_dev,
+ .read = mbochs_read,
+ .write = mbochs_write,
+ .ioctl = mbochs_ioctl,
+ .mmap = mbochs_mmap,
};
-static struct attribute_group *mdev_type_groups[] = {
- &mdev_type_group1,
- &mdev_type_group2,
- &mdev_type_group3,
- NULL,
-};
-
-static const struct mdev_parent_ops mdev_fops = {
- .owner = THIS_MODULE,
- .mdev_attr_groups = mdev_dev_groups,
- .supported_type_groups = mdev_type_groups,
- .create = mbochs_create,
- .remove = mbochs_remove,
- .open = mbochs_open,
- .release = mbochs_close,
- .read = mbochs_read,
- .write = mbochs_write,
- .ioctl = mbochs_ioctl,
- .mmap = mbochs_mmap,
+static struct mdev_driver mbochs_driver = {
+ .device_api = VFIO_DEVICE_API_PCI_STRING,
+ .driver = {
+ .name = "mbochs",
+ .owner = THIS_MODULE,
+ .mod_name = KBUILD_MODNAME,
+ .dev_groups = mdev_dev_groups,
+ },
+ .probe = mbochs_probe,
+ .remove = mbochs_remove,
+ .get_available = mbochs_get_available,
+ .show_description = mbochs_show_description,
};
static const struct file_operations vd_fops = {
@@ -1429,6 +1404,8 @@ static int __init mbochs_dev_init(void)
{
int ret = 0;
+ atomic_set(&mbochs_avail_mbytes, max_mbytes);
+
ret = alloc_chrdev_region(&mbochs_devt, 0, MINORMASK + 1, MBOCHS_NAME);
if (ret < 0) {
pr_err("Error: failed to register mbochs_dev, err: %d\n", ret);
@@ -1438,11 +1415,15 @@ static int __init mbochs_dev_init(void)
cdev_add(&mbochs_cdev, mbochs_devt, MINORMASK + 1);
pr_info("%s: major %d\n", __func__, MAJOR(mbochs_devt));
+ ret = mdev_register_driver(&mbochs_driver);
+ if (ret)
+ goto err_cdev;
+
mbochs_class = class_create(THIS_MODULE, MBOCHS_CLASS_NAME);
if (IS_ERR(mbochs_class)) {
pr_err("Error: failed to register mbochs_dev class\n");
ret = PTR_ERR(mbochs_class);
- goto failed1;
+ goto err_driver;
}
mbochs_dev.class = mbochs_class;
mbochs_dev.release = mbochs_device_release;
@@ -1450,19 +1431,23 @@ static int __init mbochs_dev_init(void)
ret = device_register(&mbochs_dev);
if (ret)
- goto failed2;
+ goto err_class;
- ret = mdev_register_device(&mbochs_dev, &mdev_fops);
+ ret = mdev_register_parent(&mbochs_parent, &mbochs_dev, &mbochs_driver,
+ mbochs_mdev_types,
+ ARRAY_SIZE(mbochs_mdev_types));
if (ret)
- goto failed3;
+ goto err_device;
return 0;
-failed3:
+err_device:
device_unregister(&mbochs_dev);
-failed2:
+err_class:
class_destroy(mbochs_class);
-failed1:
+err_driver:
+ mdev_unregister_driver(&mbochs_driver);
+err_cdev:
cdev_del(&mbochs_cdev);
unregister_chrdev_region(mbochs_devt, MINORMASK + 1);
return ret;
@@ -1471,14 +1456,16 @@ failed1:
static void __exit mbochs_dev_exit(void)
{
mbochs_dev.bus = NULL;
- mdev_unregister_device(&mbochs_dev);
+ mdev_unregister_parent(&mbochs_parent);
device_unregister(&mbochs_dev);
+ mdev_unregister_driver(&mbochs_driver);
cdev_del(&mbochs_cdev);
unregister_chrdev_region(mbochs_devt, MINORMASK + 1);
class_destroy(mbochs_class);
mbochs_class = NULL;
}
+MODULE_IMPORT_NS(DMA_BUF);
module_init(mbochs_dev_init)
module_exit(mbochs_dev_exit)
diff --git a/samples/vfio-mdev/mdpy-defs.h b/samples/vfio-mdev/mdpy-defs.h
index eb26421b6429..961c55ec3ffd 100644
--- a/samples/vfio-mdev/mdpy-defs.h
+++ b/samples/vfio-mdev/mdpy-defs.h
@@ -9,7 +9,7 @@
*/
/* pci ids */
-#define MDPY_PCI_VENDOR_ID 0x1b36 /* redhat */
+#define MDPY_PCI_VENDOR_ID PCI_VENDOR_ID_REDHAT
#define MDPY_PCI_DEVICE_ID 0x000f
#define MDPY_PCI_SUBVENDOR_ID PCI_SUBVENDOR_ID_REDHAT_QUMRANET
#define MDPY_PCI_SUBDEVICE_ID PCI_SUBDEVICE_ID_QEMU
diff --git a/samples/vfio-mdev/mdpy-fb.c b/samples/vfio-mdev/mdpy-fb.c
index 21dbf63d6e41..9ec93d90e8a5 100644
--- a/samples/vfio-mdev/mdpy-fb.c
+++ b/samples/vfio-mdev/mdpy-fb.c
@@ -117,22 +117,27 @@ static int mdpy_fb_probe(struct pci_dev *pdev,
if (format != DRM_FORMAT_XRGB8888) {
pci_err(pdev, "format mismatch (0x%x != 0x%x)\n",
format, DRM_FORMAT_XRGB8888);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_release_regions;
}
if (width < 100 || width > 10000) {
pci_err(pdev, "width (%d) out of range\n", width);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_release_regions;
}
if (height < 100 || height > 10000) {
pci_err(pdev, "height (%d) out of range\n", height);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_release_regions;
}
pci_info(pdev, "mdpy found: %dx%d framebuffer\n",
width, height);
info = framebuffer_alloc(sizeof(struct mdpy_fb_par), &pdev->dev);
- if (!info)
+ if (!info) {
+ ret = -ENOMEM;
goto err_release_regions;
+ }
pci_set_drvdata(pdev, info);
par = info->par;
diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c
index cc86bf6566e4..946e8cfde6fd 100644
--- a/samples/vfio-mdev/mdpy.c
+++ b/samples/vfio-mdev/mdpy.c
@@ -17,7 +17,6 @@
*/
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -43,36 +42,34 @@
MODULE_LICENSE("GPL v2");
-static int max_devices = 4;
-module_param_named(count, max_devices, int, 0444);
-MODULE_PARM_DESC(count, "number of " MDPY_NAME " devices");
-
-
#define MDPY_TYPE_1 "vga"
#define MDPY_TYPE_2 "xga"
#define MDPY_TYPE_3 "hd"
-static const struct mdpy_type {
- const char *name;
+static struct mdpy_type {
+ struct mdev_type type;
u32 format;
u32 bytepp;
u32 width;
u32 height;
} mdpy_types[] = {
{
- .name = MDPY_CLASS_NAME "-" MDPY_TYPE_1,
+ .type.sysfs_name = MDPY_TYPE_1,
+ .type.pretty_name = MDPY_CLASS_NAME "-" MDPY_TYPE_1,
.format = DRM_FORMAT_XRGB8888,
.bytepp = 4,
.width = 640,
.height = 480,
}, {
- .name = MDPY_CLASS_NAME "-" MDPY_TYPE_2,
+ .type.sysfs_name = MDPY_TYPE_2,
+ .type.pretty_name = MDPY_CLASS_NAME "-" MDPY_TYPE_2,
.format = DRM_FORMAT_XRGB8888,
.bytepp = 4,
.width = 1024,
.height = 768,
}, {
- .name = MDPY_CLASS_NAME "-" MDPY_TYPE_3,
+ .type.sysfs_name = MDPY_TYPE_3,
+ .type.pretty_name = MDPY_CLASS_NAME "-" MDPY_TYPE_3,
.format = DRM_FORMAT_XRGB8888,
.bytepp = 4,
.width = 1920,
@@ -80,14 +77,22 @@ static const struct mdpy_type {
},
};
+static struct mdev_type *mdpy_mdev_types[] = {
+ &mdpy_types[0].type,
+ &mdpy_types[1].type,
+ &mdpy_types[2].type,
+};
+
static dev_t mdpy_devt;
static struct class *mdpy_class;
static struct cdev mdpy_cdev;
static struct device mdpy_dev;
-static u32 mdpy_count;
+static struct mdev_parent mdpy_parent;
+static const struct vfio_device_ops mdpy_dev_ops;
/* State of each mdev device */
struct mdev_state {
+ struct vfio_device vdev;
u8 *vconfig;
u32 bar_mask;
struct mutex ops_lock;
@@ -99,16 +104,6 @@ struct mdev_state {
void *memblk;
};
-static const struct mdpy_type *mdpy_find_type(struct kobject *kobj)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mdpy_types); i++)
- if (strcmp(mdpy_types[i].name, kobj->name) == 0)
- return mdpy_types + i;
- return NULL;
-}
-
static void mdpy_create_config_space(struct mdev_state *mdev_state)
{
STORE_LE16((u16 *) &mdev_state->vconfig[PCI_VENDOR_ID],
@@ -172,11 +167,9 @@ static void handle_pci_cfg_write(struct mdev_state *mdev_state, u16 offset,
}
}
-static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count,
- loff_t pos, bool is_write)
+static ssize_t mdev_access(struct mdev_state *mdev_state, char *buf,
+ size_t count, loff_t pos, bool is_write)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
- struct device *dev = mdev_dev(mdev);
int ret = 0;
mutex_lock(&mdev_state->ops_lock);
@@ -197,8 +190,9 @@ static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count,
memcpy(buf, mdev_state->memblk, count);
} else {
- dev_info(dev, "%s: %s @0x%llx (unhandled)\n",
- __func__, is_write ? "WR" : "RD", pos);
+ dev_info(mdev_state->vdev.dev,
+ "%s: %s @0x%llx (unhandled)\n", __func__,
+ is_write ? "WR" : "RD", pos);
ret = -1;
goto accessfailed;
}
@@ -212,9 +206,8 @@ accessfailed:
return ret;
}
-static int mdpy_reset(struct mdev_device *mdev)
+static int mdpy_reset(struct mdev_state *mdev_state)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
u32 stride, i;
/* initialize with gray gradient */
@@ -226,71 +219,88 @@ static int mdpy_reset(struct mdev_device *mdev)
return 0;
}
-static int mdpy_create(struct kobject *kobj, struct mdev_device *mdev)
+static int mdpy_init_dev(struct vfio_device *vdev)
{
- const struct mdpy_type *type = mdpy_find_type(kobj);
- struct device *dev = mdev_dev(mdev);
- struct mdev_state *mdev_state;
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
+ struct mdev_device *mdev = to_mdev_device(vdev->dev);
+ const struct mdpy_type *type =
+ container_of(mdev->type, struct mdpy_type, type);
u32 fbsize;
-
- if (mdpy_count >= max_devices)
- return -ENOMEM;
-
- mdev_state = kzalloc(sizeof(struct mdev_state), GFP_KERNEL);
- if (mdev_state == NULL)
- return -ENOMEM;
+ int ret = -ENOMEM;
mdev_state->vconfig = kzalloc(MDPY_CONFIG_SPACE_SIZE, GFP_KERNEL);
- if (mdev_state->vconfig == NULL) {
- kfree(mdev_state);
- return -ENOMEM;
- }
+ if (!mdev_state->vconfig)
+ return ret;
- if (!type)
- type = &mdpy_types[0];
fbsize = roundup_pow_of_two(type->width * type->height * type->bytepp);
mdev_state->memblk = vmalloc_user(fbsize);
- if (!mdev_state->memblk) {
- kfree(mdev_state->vconfig);
- kfree(mdev_state);
- return -ENOMEM;
- }
- dev_info(dev, "%s: %s (%dx%d)\n",
- __func__, kobj->name, type->width, type->height);
+ if (!mdev_state->memblk)
+ goto out_vconfig;
mutex_init(&mdev_state->ops_lock);
mdev_state->mdev = mdev;
- mdev_set_drvdata(mdev, mdev_state);
-
- mdev_state->type = type;
+ mdev_state->type = type;
mdev_state->memsize = fbsize;
mdpy_create_config_space(mdev_state);
- mdpy_reset(mdev);
+ mdpy_reset(mdev_state);
- mdpy_count++;
+ dev_info(vdev->dev, "%s: %s (%dx%d)\n", __func__, type->type.pretty_name,
+ type->width, type->height);
return 0;
+
+out_vconfig:
+ kfree(mdev_state->vconfig);
+ return ret;
}
-static int mdpy_remove(struct mdev_device *mdev)
+static int mdpy_probe(struct mdev_device *mdev)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
- struct device *dev = mdev_dev(mdev);
+ struct mdev_state *mdev_state;
+ int ret;
+
+ mdev_state = vfio_alloc_device(mdev_state, vdev, &mdev->dev,
+ &mdpy_dev_ops);
+ if (IS_ERR(mdev_state))
+ return PTR_ERR(mdev_state);
+
+ ret = vfio_register_emulated_iommu_dev(&mdev_state->vdev);
+ if (ret)
+ goto err_put_vdev;
+ dev_set_drvdata(&mdev->dev, mdev_state);
+ return 0;
- dev_info(dev, "%s\n", __func__);
+err_put_vdev:
+ vfio_put_device(&mdev_state->vdev);
+ return ret;
+}
+
+static void mdpy_release_dev(struct vfio_device *vdev)
+{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
- mdev_set_drvdata(mdev, NULL);
vfree(mdev_state->memblk);
kfree(mdev_state->vconfig);
- kfree(mdev_state);
+ vfio_free_device(vdev);
+}
- mdpy_count--;
- return 0;
+static void mdpy_remove(struct mdev_device *mdev)
+{
+ struct mdev_state *mdev_state = dev_get_drvdata(&mdev->dev);
+
+ dev_info(&mdev->dev, "%s\n", __func__);
+
+ vfio_unregister_group_dev(&mdev_state->vdev);
+ vfio_put_device(&mdev_state->vdev);
}
-static ssize_t mdpy_read(struct mdev_device *mdev, char __user *buf,
+static ssize_t mdpy_read(struct vfio_device *vdev, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
unsigned int done = 0;
int ret;
@@ -300,8 +310,8 @@ static ssize_t mdpy_read(struct mdev_device *mdev, char __user *buf,
if (count >= 4 && !(*ppos % 4)) {
u32 val;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
- *ppos, false);
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
+ *ppos, false);
if (ret <= 0)
goto read_err;
@@ -312,7 +322,7 @@ static ssize_t mdpy_read(struct mdev_device *mdev, char __user *buf,
} else if (count >= 2 && !(*ppos % 2)) {
u16 val;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -324,7 +334,7 @@ static ssize_t mdpy_read(struct mdev_device *mdev, char __user *buf,
} else {
u8 val;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -347,9 +357,11 @@ read_err:
return -EFAULT;
}
-static ssize_t mdpy_write(struct mdev_device *mdev, const char __user *buf,
+static ssize_t mdpy_write(struct vfio_device *vdev, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
unsigned int done = 0;
int ret;
@@ -362,7 +374,7 @@ static ssize_t mdpy_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -374,7 +386,7 @@ static ssize_t mdpy_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -386,7 +398,7 @@ static ssize_t mdpy_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (char *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (char *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -404,9 +416,10 @@ write_err:
return -EFAULT;
}
-static int mdpy_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
+static int mdpy_mmap(struct vfio_device *vdev, struct vm_area_struct *vma)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
if (vma->vm_pgoff != MDPY_MEMORY_BAR_OFFSET >> PAGE_SHIFT)
return -EINVAL;
@@ -417,21 +430,13 @@ static int mdpy_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
if ((vma->vm_flags & VM_SHARED) == 0)
return -EINVAL;
- return remap_vmalloc_range_partial(vma, vma->vm_start,
- mdev_state->memblk,
- vma->vm_end - vma->vm_start);
+ return remap_vmalloc_range(vma, mdev_state->memblk, 0);
}
-static int mdpy_get_region_info(struct mdev_device *mdev,
+static int mdpy_get_region_info(struct mdev_state *mdev_state,
struct vfio_region_info *region_info,
u16 *cap_type_id, void **cap_type)
{
- struct mdev_state *mdev_state;
-
- mdev_state = mdev_get_drvdata(mdev);
- if (!mdev_state)
- return -EINVAL;
-
if (region_info->index >= VFIO_PCI_NUM_REGIONS &&
region_info->index != MDPY_DISPLAY_REGION)
return -EINVAL;
@@ -460,15 +465,13 @@ static int mdpy_get_region_info(struct mdev_device *mdev,
return 0;
}
-static int mdpy_get_irq_info(struct mdev_device *mdev,
- struct vfio_irq_info *irq_info)
+static int mdpy_get_irq_info(struct vfio_irq_info *irq_info)
{
irq_info->count = 0;
return 0;
}
-static int mdpy_get_device_info(struct mdev_device *mdev,
- struct vfio_device_info *dev_info)
+static int mdpy_get_device_info(struct vfio_device_info *dev_info)
{
dev_info->flags = VFIO_DEVICE_FLAGS_PCI;
dev_info->num_regions = VFIO_PCI_NUM_REGIONS;
@@ -476,11 +479,9 @@ static int mdpy_get_device_info(struct mdev_device *mdev,
return 0;
}
-static int mdpy_query_gfx_plane(struct mdev_device *mdev,
+static int mdpy_query_gfx_plane(struct mdev_state *mdev_state,
struct vfio_device_gfx_plane_info *plane)
{
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
-
if (plane->flags & VFIO_GFX_PLANE_TYPE_PROBE) {
if (plane->flags == (VFIO_GFX_PLANE_TYPE_PROBE |
VFIO_GFX_PLANE_TYPE_REGION))
@@ -509,14 +510,13 @@ static int mdpy_query_gfx_plane(struct mdev_device *mdev,
return 0;
}
-static long mdpy_ioctl(struct mdev_device *mdev, unsigned int cmd,
+static long mdpy_ioctl(struct vfio_device *vdev, unsigned int cmd,
unsigned long arg)
{
int ret = 0;
unsigned long minsz;
- struct mdev_state *mdev_state;
-
- mdev_state = mdev_get_drvdata(mdev);
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
switch (cmd) {
case VFIO_DEVICE_GET_INFO:
@@ -531,7 +531,7 @@ static long mdpy_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (info.argsz < minsz)
return -EINVAL;
- ret = mdpy_get_device_info(mdev, &info);
+ ret = mdpy_get_device_info(&info);
if (ret)
return ret;
@@ -556,7 +556,7 @@ static long mdpy_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (info.argsz < minsz)
return -EINVAL;
- ret = mdpy_get_region_info(mdev, &info, &cap_type_id,
+ ret = mdpy_get_region_info(mdev_state, &info, &cap_type_id,
&cap_type);
if (ret)
return ret;
@@ -580,7 +580,7 @@ static long mdpy_ioctl(struct mdev_device *mdev, unsigned int cmd,
(info.index >= mdev_state->dev_info.num_irqs))
return -EINVAL;
- ret = mdpy_get_irq_info(mdev, &info);
+ ret = mdpy_get_irq_info(&info);
if (ret)
return ret;
@@ -603,7 +603,7 @@ static long mdpy_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (plane.argsz < minsz)
return -EINVAL;
- ret = mdpy_query_gfx_plane(mdev, &plane);
+ ret = mdpy_query_gfx_plane(mdev_state, &plane);
if (ret)
return ret;
@@ -617,30 +617,16 @@ static long mdpy_ioctl(struct mdev_device *mdev, unsigned int cmd,
return -EINVAL;
case VFIO_DEVICE_RESET:
- return mdpy_reset(mdev);
+ return mdpy_reset(mdev_state);
}
return -ENOTTY;
}
-static int mdpy_open(struct mdev_device *mdev)
-{
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
- return 0;
-}
-
-static void mdpy_close(struct mdev_device *mdev)
-{
- module_put(THIS_MODULE);
-}
-
static ssize_t
resolution_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct mdev_device *mdev = mdev_from_dev(dev);
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
+ struct mdev_state *mdev_state = dev_get_drvdata(dev);
return sprintf(buf, "%dx%d\n",
mdev_state->type->width,
@@ -658,85 +644,40 @@ static const struct attribute_group mdev_dev_group = {
.attrs = mdev_dev_attrs,
};
-const struct attribute_group *mdev_dev_groups[] = {
+static const struct attribute_group *mdev_dev_groups[] = {
&mdev_dev_group,
NULL,
};
-static ssize_t
-name_show(struct kobject *kobj, struct device *dev, char *buf)
+static ssize_t mdpy_show_description(struct mdev_type *mtype, char *buf)
{
- return sprintf(buf, "%s\n", kobj->name);
-}
-MDEV_TYPE_ATTR_RO(name);
-
-static ssize_t
-description_show(struct kobject *kobj, struct device *dev, char *buf)
-{
- const struct mdpy_type *type = mdpy_find_type(kobj);
+ struct mdpy_type *type = container_of(mtype, struct mdpy_type, type);
return sprintf(buf, "virtual display, %dx%d framebuffer\n",
- type ? type->width : 0,
- type ? type->height : 0);
-}
-MDEV_TYPE_ATTR_RO(description);
-
-static ssize_t
-available_instances_show(struct kobject *kobj, struct device *dev, char *buf)
-{
- return sprintf(buf, "%d\n", max_devices - mdpy_count);
+ type->width, type->height);
}
-MDEV_TYPE_ATTR_RO(available_instances);
-
-static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
- char *buf)
-{
- return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
-}
-MDEV_TYPE_ATTR_RO(device_api);
-
-static struct attribute *mdev_types_attrs[] = {
- &mdev_type_attr_name.attr,
- &mdev_type_attr_description.attr,
- &mdev_type_attr_device_api.attr,
- &mdev_type_attr_available_instances.attr,
- NULL,
-};
-static struct attribute_group mdev_type_group1 = {
- .name = MDPY_TYPE_1,
- .attrs = mdev_types_attrs,
+static const struct vfio_device_ops mdpy_dev_ops = {
+ .init = mdpy_init_dev,
+ .release = mdpy_release_dev,
+ .read = mdpy_read,
+ .write = mdpy_write,
+ .ioctl = mdpy_ioctl,
+ .mmap = mdpy_mmap,
};
-static struct attribute_group mdev_type_group2 = {
- .name = MDPY_TYPE_2,
- .attrs = mdev_types_attrs,
-};
-
-static struct attribute_group mdev_type_group3 = {
- .name = MDPY_TYPE_3,
- .attrs = mdev_types_attrs,
-};
-
-static struct attribute_group *mdev_type_groups[] = {
- &mdev_type_group1,
- &mdev_type_group2,
- &mdev_type_group3,
- NULL,
-};
-
-static const struct mdev_parent_ops mdev_fops = {
- .owner = THIS_MODULE,
- .mdev_attr_groups = mdev_dev_groups,
- .supported_type_groups = mdev_type_groups,
- .create = mdpy_create,
- .remove = mdpy_remove,
- .open = mdpy_open,
- .release = mdpy_close,
- .read = mdpy_read,
- .write = mdpy_write,
- .ioctl = mdpy_ioctl,
- .mmap = mdpy_mmap,
+static struct mdev_driver mdpy_driver = {
+ .device_api = VFIO_DEVICE_API_PCI_STRING,
+ .max_instances = 4,
+ .driver = {
+ .name = "mdpy",
+ .owner = THIS_MODULE,
+ .mod_name = KBUILD_MODNAME,
+ .dev_groups = mdev_dev_groups,
+ },
+ .probe = mdpy_probe,
+ .remove = mdpy_remove,
+ .show_description = mdpy_show_description,
};
static const struct file_operations vd_fops = {
@@ -761,11 +702,15 @@ static int __init mdpy_dev_init(void)
cdev_add(&mdpy_cdev, mdpy_devt, MINORMASK + 1);
pr_info("%s: major %d\n", __func__, MAJOR(mdpy_devt));
+ ret = mdev_register_driver(&mdpy_driver);
+ if (ret)
+ goto err_cdev;
+
mdpy_class = class_create(THIS_MODULE, MDPY_CLASS_NAME);
if (IS_ERR(mdpy_class)) {
pr_err("Error: failed to register mdpy_dev class\n");
ret = PTR_ERR(mdpy_class);
- goto failed1;
+ goto err_driver;
}
mdpy_dev.class = mdpy_class;
mdpy_dev.release = mdpy_device_release;
@@ -773,19 +718,23 @@ static int __init mdpy_dev_init(void)
ret = device_register(&mdpy_dev);
if (ret)
- goto failed2;
+ goto err_class;
- ret = mdev_register_device(&mdpy_dev, &mdev_fops);
+ ret = mdev_register_parent(&mdpy_parent, &mdpy_dev, &mdpy_driver,
+ mdpy_mdev_types,
+ ARRAY_SIZE(mdpy_mdev_types));
if (ret)
- goto failed3;
+ goto err_device;
return 0;
-failed3:
+err_device:
device_unregister(&mdpy_dev);
-failed2:
+err_class:
class_destroy(mdpy_class);
-failed1:
+err_driver:
+ mdev_unregister_driver(&mdpy_driver);
+err_cdev:
cdev_del(&mdpy_cdev);
unregister_chrdev_region(mdpy_devt, MINORMASK + 1);
return ret;
@@ -794,14 +743,18 @@ failed1:
static void __exit mdpy_dev_exit(void)
{
mdpy_dev.bus = NULL;
- mdev_unregister_device(&mdpy_dev);
+ mdev_unregister_parent(&mdpy_parent);
device_unregister(&mdpy_dev);
+ mdev_unregister_driver(&mdpy_driver);
cdev_del(&mdpy_cdev);
unregister_chrdev_region(mdpy_devt, MINORMASK + 1);
class_destroy(mdpy_class);
mdpy_class = NULL;
}
+module_param_named(count, mdpy_driver.max_instances, int, 0444);
+MODULE_PARM_DESC(count, "number of " MDPY_NAME " devices");
+
module_init(mdpy_dev_init)
module_exit(mdpy_dev_exit)
diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c
index ce84a300a4da..e72085fc1376 100644
--- a/samples/vfio-mdev/mtty.c
+++ b/samples/vfio-mdev/mtty.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/poll.h>
@@ -20,7 +19,6 @@
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/wait.h>
-#include <linux/uuid.h>
#include <linux/vfio.h>
#include <linux/iommu.h>
#include <linux/sysfs.h>
@@ -74,6 +72,7 @@ static struct mtty_dev {
struct cdev vd_cdev;
struct idr vd_idr;
struct device dev;
+ struct mdev_parent parent;
} mtty_dev;
struct mdev_region_info {
@@ -127,6 +126,7 @@ struct serial_port {
/* State of each mdev device */
struct mdev_state {
+ struct vfio_device vdev;
int irq_fd;
struct eventfd_ctx *intx_evtfd;
struct eventfd_ctx *msi_evtfd;
@@ -143,13 +143,29 @@ struct mdev_state {
int nr_ports;
};
-static struct mutex mdev_list_lock;
-static struct list_head mdev_devices_list;
+static struct mtty_type {
+ struct mdev_type type;
+ int nr_ports;
+} mtty_types[2] = {
+ { .nr_ports = 1, .type.sysfs_name = "1",
+ .type.pretty_name = "Single port serial" },
+ { .nr_ports = 2, .type.sysfs_name = "2",
+ .type.pretty_name = "Dual port serial" },
+};
+
+static struct mdev_type *mtty_mdev_types[] = {
+ &mtty_types[0].type,
+ &mtty_types[1].type,
+};
+
+static atomic_t mdev_avail_ports = ATOMIC_INIT(MAX_MTTYS);
static const struct file_operations vd_fops = {
.owner = THIS_MODULE,
};
+static const struct vfio_device_ops mtty_dev_ops;
+
/* function prototypes */
static int mtty_trigger_interrupt(struct mdev_state *mdev_state);
@@ -631,23 +647,16 @@ static void mdev_read_base(struct mdev_state *mdev_state)
}
}
-static ssize_t mdev_access(struct mdev_device *mdev, u8 *buf, size_t count,
+static ssize_t mdev_access(struct mdev_state *mdev_state, u8 *buf, size_t count,
loff_t pos, bool is_write)
{
- struct mdev_state *mdev_state;
unsigned int index;
loff_t offset;
int ret = 0;
- if (!mdev || !buf)
+ if (!buf)
return -EINVAL;
- mdev_state = mdev_get_drvdata(mdev);
- if (!mdev_state) {
- pr_err("%s mdev_state not found\n", __func__);
- return -EINVAL;
- }
-
mutex_lock(&mdev_state->ops_lock);
index = MTTY_VFIO_PCI_OFFSET_TO_INDEX(pos);
@@ -708,97 +717,96 @@ accessfailed:
return ret;
}
-static int mtty_create(struct kobject *kobj, struct mdev_device *mdev)
+static int mtty_init_dev(struct vfio_device *vdev)
{
- struct mdev_state *mdev_state;
- char name[MTTY_STRING_LEN];
- int nr_ports = 0, i;
-
- if (!mdev)
- return -EINVAL;
-
- for (i = 0; i < 2; i++) {
- snprintf(name, MTTY_STRING_LEN, "%s-%d",
- dev_driver_string(mdev_parent_dev(mdev)), i + 1);
- if (!strcmp(kobj->name, name)) {
- nr_ports = i + 1;
- break;
- }
- }
-
- if (!nr_ports)
- return -EINVAL;
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
+ struct mdev_device *mdev = to_mdev_device(vdev->dev);
+ struct mtty_type *type =
+ container_of(mdev->type, struct mtty_type, type);
+ int avail_ports = atomic_read(&mdev_avail_ports);
+ int ret;
- mdev_state = kzalloc(sizeof(struct mdev_state), GFP_KERNEL);
- if (mdev_state == NULL)
- return -ENOMEM;
+ do {
+ if (avail_ports < type->nr_ports)
+ return -ENOSPC;
+ } while (!atomic_try_cmpxchg(&mdev_avail_ports,
+ &avail_ports,
+ avail_ports - type->nr_ports));
- mdev_state->nr_ports = nr_ports;
+ mdev_state->nr_ports = type->nr_ports;
mdev_state->irq_index = -1;
mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE;
mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE;
mutex_init(&mdev_state->rxtx_lock);
- mdev_state->vconfig = kzalloc(MTTY_CONFIG_SPACE_SIZE, GFP_KERNEL);
- if (mdev_state->vconfig == NULL) {
- kfree(mdev_state);
- return -ENOMEM;
+ mdev_state->vconfig = kzalloc(MTTY_CONFIG_SPACE_SIZE, GFP_KERNEL);
+ if (!mdev_state->vconfig) {
+ ret = -ENOMEM;
+ goto err_nr_ports;
}
mutex_init(&mdev_state->ops_lock);
mdev_state->mdev = mdev;
- mdev_set_drvdata(mdev, mdev_state);
-
mtty_create_config_space(mdev_state);
-
- mutex_lock(&mdev_list_lock);
- list_add(&mdev_state->next, &mdev_devices_list);
- mutex_unlock(&mdev_list_lock);
-
return 0;
+
+err_nr_ports:
+ atomic_add(type->nr_ports, &mdev_avail_ports);
+ return ret;
}
-static int mtty_remove(struct mdev_device *mdev)
+static int mtty_probe(struct mdev_device *mdev)
{
- struct mdev_state *mds, *tmp_mds;
- struct mdev_state *mdev_state = mdev_get_drvdata(mdev);
- int ret = -EINVAL;
-
- mutex_lock(&mdev_list_lock);
- list_for_each_entry_safe(mds, tmp_mds, &mdev_devices_list, next) {
- if (mdev_state == mds) {
- list_del(&mdev_state->next);
- mdev_set_drvdata(mdev, NULL);
- kfree(mdev_state->vconfig);
- kfree(mdev_state);
- ret = 0;
- break;
- }
- }
- mutex_unlock(&mdev_list_lock);
+ struct mdev_state *mdev_state;
+ int ret;
+
+ mdev_state = vfio_alloc_device(mdev_state, vdev, &mdev->dev,
+ &mtty_dev_ops);
+ if (IS_ERR(mdev_state))
+ return PTR_ERR(mdev_state);
+
+ ret = vfio_register_emulated_iommu_dev(&mdev_state->vdev);
+ if (ret)
+ goto err_put_vdev;
+ dev_set_drvdata(&mdev->dev, mdev_state);
+ return 0;
+err_put_vdev:
+ vfio_put_device(&mdev_state->vdev);
return ret;
}
-static int mtty_reset(struct mdev_device *mdev)
+static void mtty_release_dev(struct vfio_device *vdev)
{
- struct mdev_state *mdev_state;
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
- if (!mdev)
- return -EINVAL;
+ atomic_add(mdev_state->nr_ports, &mdev_avail_ports);
+ kfree(mdev_state->vconfig);
+ vfio_free_device(vdev);
+}
- mdev_state = mdev_get_drvdata(mdev);
- if (!mdev_state)
- return -EINVAL;
+static void mtty_remove(struct mdev_device *mdev)
+{
+ struct mdev_state *mdev_state = dev_get_drvdata(&mdev->dev);
+ vfio_unregister_group_dev(&mdev_state->vdev);
+ vfio_put_device(&mdev_state->vdev);
+}
+
+static int mtty_reset(struct mdev_state *mdev_state)
+{
pr_info("%s: called\n", __func__);
return 0;
}
-static ssize_t mtty_read(struct mdev_device *mdev, char __user *buf,
+static ssize_t mtty_read(struct vfio_device *vdev, char __user *buf,
size_t count, loff_t *ppos)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
unsigned int done = 0;
int ret;
@@ -808,7 +816,7 @@ static ssize_t mtty_read(struct mdev_device *mdev, char __user *buf,
if (count >= 4 && !(*ppos % 4)) {
u32 val;
- ret = mdev_access(mdev, (u8 *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -820,7 +828,7 @@ static ssize_t mtty_read(struct mdev_device *mdev, char __user *buf,
} else if (count >= 2 && !(*ppos % 2)) {
u16 val;
- ret = mdev_access(mdev, (u8 *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -832,7 +840,7 @@ static ssize_t mtty_read(struct mdev_device *mdev, char __user *buf,
} else {
u8 val;
- ret = mdev_access(mdev, (u8 *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val),
*ppos, false);
if (ret <= 0)
goto read_err;
@@ -855,9 +863,11 @@ read_err:
return -EFAULT;
}
-static ssize_t mtty_write(struct mdev_device *mdev, const char __user *buf,
+static ssize_t mtty_write(struct vfio_device *vdev, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
unsigned int done = 0;
int ret;
@@ -870,7 +880,7 @@ static ssize_t mtty_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (u8 *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -882,7 +892,7 @@ static ssize_t mtty_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (u8 *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -894,7 +904,7 @@ static ssize_t mtty_write(struct mdev_device *mdev, const char __user *buf,
if (copy_from_user(&val, buf, sizeof(val)))
goto write_err;
- ret = mdev_access(mdev, (u8 *)&val, sizeof(val),
+ ret = mdev_access(mdev_state, (u8 *)&val, sizeof(val),
*ppos, true);
if (ret <= 0)
goto write_err;
@@ -912,19 +922,11 @@ write_err:
return -EFAULT;
}
-static int mtty_set_irqs(struct mdev_device *mdev, uint32_t flags,
+static int mtty_set_irqs(struct mdev_state *mdev_state, uint32_t flags,
unsigned int index, unsigned int start,
unsigned int count, void *data)
{
int ret = 0;
- struct mdev_state *mdev_state;
-
- if (!mdev)
- return -EINVAL;
-
- mdev_state = mdev_get_drvdata(mdev);
- if (!mdev_state)
- return -EINVAL;
mutex_lock(&mdev_state->ops_lock);
switch (index) {
@@ -1040,21 +1042,13 @@ static int mtty_trigger_interrupt(struct mdev_state *mdev_state)
return ret;
}
-static int mtty_get_region_info(struct mdev_device *mdev,
+static int mtty_get_region_info(struct mdev_state *mdev_state,
struct vfio_region_info *region_info,
u16 *cap_type_id, void **cap_type)
{
unsigned int size = 0;
- struct mdev_state *mdev_state;
u32 bar_index;
- if (!mdev)
- return -EINVAL;
-
- mdev_state = mdev_get_drvdata(mdev);
- if (!mdev_state)
- return -EINVAL;
-
bar_index = region_info->index;
if (bar_index >= VFIO_PCI_NUM_REGIONS)
return -EINVAL;
@@ -1089,8 +1083,7 @@ static int mtty_get_region_info(struct mdev_device *mdev,
return 0;
}
-static int mtty_get_irq_info(struct mdev_device *mdev,
- struct vfio_irq_info *irq_info)
+static int mtty_get_irq_info(struct vfio_irq_info *irq_info)
{
switch (irq_info->index) {
case VFIO_PCI_INTX_IRQ_INDEX:
@@ -1114,8 +1107,7 @@ static int mtty_get_irq_info(struct mdev_device *mdev,
return 0;
}
-static int mtty_get_device_info(struct mdev_device *mdev,
- struct vfio_device_info *dev_info)
+static int mtty_get_device_info(struct vfio_device_info *dev_info)
{
dev_info->flags = VFIO_DEVICE_FLAGS_PCI;
dev_info->num_regions = VFIO_PCI_NUM_REGIONS;
@@ -1124,19 +1116,13 @@ static int mtty_get_device_info(struct mdev_device *mdev,
return 0;
}
-static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
+static long mtty_ioctl(struct vfio_device *vdev, unsigned int cmd,
unsigned long arg)
{
+ struct mdev_state *mdev_state =
+ container_of(vdev, struct mdev_state, vdev);
int ret = 0;
unsigned long minsz;
- struct mdev_state *mdev_state;
-
- if (!mdev)
- return -EINVAL;
-
- mdev_state = mdev_get_drvdata(mdev);
- if (!mdev_state)
- return -ENODEV;
switch (cmd) {
case VFIO_DEVICE_GET_INFO:
@@ -1151,7 +1137,7 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (info.argsz < minsz)
return -EINVAL;
- ret = mtty_get_device_info(mdev, &info);
+ ret = mtty_get_device_info(&info);
if (ret)
return ret;
@@ -1176,7 +1162,7 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
if (info.argsz < minsz)
return -EINVAL;
- ret = mtty_get_region_info(mdev, &info, &cap_type_id,
+ ret = mtty_get_region_info(mdev_state, &info, &cap_type_id,
&cap_type);
if (ret)
return ret;
@@ -1200,7 +1186,7 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
(info.index >= mdev_state->dev_info.num_irqs))
return -EINVAL;
- ret = mtty_get_irq_info(mdev, &info);
+ ret = mtty_get_irq_info(&info);
if (ret)
return ret;
@@ -1234,61 +1220,23 @@ static long mtty_ioctl(struct mdev_device *mdev, unsigned int cmd,
return PTR_ERR(data);
}
- ret = mtty_set_irqs(mdev, hdr.flags, hdr.index, hdr.start,
+ ret = mtty_set_irqs(mdev_state, hdr.flags, hdr.index, hdr.start,
hdr.count, data);
kfree(ptr);
return ret;
}
case VFIO_DEVICE_RESET:
- return mtty_reset(mdev);
+ return mtty_reset(mdev_state);
}
return -ENOTTY;
}
-static int mtty_open(struct mdev_device *mdev)
-{
- pr_info("%s\n", __func__);
- return 0;
-}
-
-static void mtty_close(struct mdev_device *mdev)
-{
- pr_info("%s\n", __func__);
-}
-
-static ssize_t
-sample_mtty_dev_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "This is phy device\n");
-}
-
-static DEVICE_ATTR_RO(sample_mtty_dev);
-
-static struct attribute *mtty_dev_attrs[] = {
- &dev_attr_sample_mtty_dev.attr,
- NULL,
-};
-
-static const struct attribute_group mtty_dev_group = {
- .name = "mtty_dev",
- .attrs = mtty_dev_attrs,
-};
-
-static const struct attribute_group *mtty_dev_groups[] = {
- &mtty_dev_group,
- NULL,
-};
-
static ssize_t
sample_mdev_dev_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- if (mdev_from_dev(dev))
- return sprintf(buf, "This is MDEV %s\n", dev_name(dev));
-
- return sprintf(buf, "\n");
+ return sprintf(buf, "This is MDEV %s\n", dev_name(dev));
}
static DEVICE_ATTR_RO(sample_mdev_dev);
@@ -1308,97 +1256,33 @@ static const struct attribute_group *mdev_dev_groups[] = {
NULL,
};
-static ssize_t
-name_show(struct kobject *kobj, struct device *dev, char *buf)
+static unsigned int mtty_get_available(struct mdev_type *mtype)
{
- char name[MTTY_STRING_LEN];
- int i;
- const char *name_str[2] = {"Single port serial", "Dual port serial"};
+ struct mtty_type *type = container_of(mtype, struct mtty_type, type);
- for (i = 0; i < 2; i++) {
- snprintf(name, MTTY_STRING_LEN, "%s-%d",
- dev_driver_string(dev), i + 1);
- if (!strcmp(kobj->name, name))
- return sprintf(buf, "%s\n", name_str[i]);
- }
-
- return -EINVAL;
+ return atomic_read(&mdev_avail_ports) / type->nr_ports;
}
-static MDEV_TYPE_ATTR_RO(name);
-
-static ssize_t
-available_instances_show(struct kobject *kobj, struct device *dev, char *buf)
-{
- char name[MTTY_STRING_LEN];
- int i;
- struct mdev_state *mds;
- int ports = 0, used = 0;
-
- for (i = 0; i < 2; i++) {
- snprintf(name, MTTY_STRING_LEN, "%s-%d",
- dev_driver_string(dev), i + 1);
- if (!strcmp(kobj->name, name)) {
- ports = i + 1;
- break;
- }
- }
-
- if (!ports)
- return -EINVAL;
-
- list_for_each_entry(mds, &mdev_devices_list, next)
- used += mds->nr_ports;
-
- return sprintf(buf, "%d\n", (MAX_MTTYS - used)/ports);
-}
-
-static MDEV_TYPE_ATTR_RO(available_instances);
-
-
-static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
- char *buf)
-{
- return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
-}
-
-static MDEV_TYPE_ATTR_RO(device_api);
-
-static struct attribute *mdev_types_attrs[] = {
- &mdev_type_attr_name.attr,
- &mdev_type_attr_device_api.attr,
- &mdev_type_attr_available_instances.attr,
- NULL,
+static const struct vfio_device_ops mtty_dev_ops = {
+ .name = "vfio-mtty",
+ .init = mtty_init_dev,
+ .release = mtty_release_dev,
+ .read = mtty_read,
+ .write = mtty_write,
+ .ioctl = mtty_ioctl,
};
-static struct attribute_group mdev_type_group1 = {
- .name = "1",
- .attrs = mdev_types_attrs,
-};
-
-static struct attribute_group mdev_type_group2 = {
- .name = "2",
- .attrs = mdev_types_attrs,
-};
-
-static struct attribute_group *mdev_type_groups[] = {
- &mdev_type_group1,
- &mdev_type_group2,
- NULL,
-};
-
-static const struct mdev_parent_ops mdev_fops = {
- .owner = THIS_MODULE,
- .dev_attr_groups = mtty_dev_groups,
- .mdev_attr_groups = mdev_dev_groups,
- .supported_type_groups = mdev_type_groups,
- .create = mtty_create,
- .remove = mtty_remove,
- .open = mtty_open,
- .release = mtty_close,
- .read = mtty_read,
- .write = mtty_write,
- .ioctl = mtty_ioctl,
+static struct mdev_driver mtty_driver = {
+ .device_api = VFIO_DEVICE_API_PCI_STRING,
+ .driver = {
+ .name = "mtty",
+ .owner = THIS_MODULE,
+ .mod_name = KBUILD_MODNAME,
+ .dev_groups = mdev_dev_groups,
+ },
+ .probe = mtty_probe,
+ .remove = mtty_remove,
+ .get_available = mtty_get_available,
};
static void mtty_device_release(struct device *dev)
@@ -1429,12 +1313,16 @@ static int __init mtty_dev_init(void)
pr_info("major_number:%d\n", MAJOR(mtty_dev.vd_devt));
+ ret = mdev_register_driver(&mtty_driver);
+ if (ret)
+ goto err_cdev;
+
mtty_dev.vd_class = class_create(THIS_MODULE, MTTY_CLASS_NAME);
if (IS_ERR(mtty_dev.vd_class)) {
pr_err("Error: failed to register mtty_dev class\n");
ret = PTR_ERR(mtty_dev.vd_class);
- goto failed1;
+ goto err_driver;
}
mtty_dev.dev.class = mtty_dev.vd_class;
@@ -1443,38 +1331,35 @@ static int __init mtty_dev_init(void)
ret = device_register(&mtty_dev.dev);
if (ret)
- goto failed2;
+ goto err_class;
- ret = mdev_register_device(&mtty_dev.dev, &mdev_fops);
+ ret = mdev_register_parent(&mtty_dev.parent, &mtty_dev.dev,
+ &mtty_driver, mtty_mdev_types,
+ ARRAY_SIZE(mtty_mdev_types));
if (ret)
- goto failed3;
-
- mutex_init(&mdev_list_lock);
- INIT_LIST_HEAD(&mdev_devices_list);
-
- goto all_done;
-
-failed3:
+ goto err_device;
+ return 0;
+err_device:
device_unregister(&mtty_dev.dev);
-failed2:
+err_class:
class_destroy(mtty_dev.vd_class);
-
-failed1:
+err_driver:
+ mdev_unregister_driver(&mtty_driver);
+err_cdev:
cdev_del(&mtty_dev.vd_cdev);
unregister_chrdev_region(mtty_dev.vd_devt, MINORMASK + 1);
-
-all_done:
return ret;
}
static void __exit mtty_dev_exit(void)
{
mtty_dev.dev.bus = NULL;
- mdev_unregister_device(&mtty_dev.dev);
+ mdev_unregister_parent(&mtty_dev.parent);
device_unregister(&mtty_dev.dev);
idr_destroy(&mtty_dev.vd_idr);
+ mdev_unregister_driver(&mtty_driver);
cdev_del(&mtty_dev.vd_cdev);
unregister_chrdev_region(mtty_dev.vd_devt, MINORMASK + 1);
class_destroy(mtty_dev.vd_class);