This patch implements a mediated virtio bus over mdev framework. This
will be used by the future virtio-mdev and vhost-mdev on top to allow
driver from either userspace or kernel to control the device which is
capable of offloading virtio datapath.

Signed-off-by: Jason Wang <jasow...@redhat.com>
---
 MAINTAINERS                       |   2 +
 drivers/mdev/Kconfig              |  10 ++
 drivers/mdev/Makefile             |   2 +
 drivers/mdev/virtio.c             | 126 +++++++++++++++++++++++
 include/linux/mdev_virtio.h       | 163 ++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h   |   8 ++
 scripts/mod/devicetable-offsets.c |   3 +
 scripts/mod/file2alias.c          |  12 +++
 8 files changed, 326 insertions(+)
 create mode 100644 drivers/mdev/virtio.c
 create mode 100644 include/linux/mdev_virtio.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 829428d8a9f5..4c2e41641f7a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17251,6 +17251,8 @@ F:      include/linux/virtio*.h
 F:     include/uapi/linux/virtio_*.h
 F:     drivers/crypto/virtio/
 F:     mm/balloon_compaction.c
+F:     include/linux/mdev_virtio.h
+F:     drivers/mdev/virtio.c
 
 VIRTIO BLOCK AND SCSI DRIVERS
 M:     "Michael S. Tsirkin" <m...@redhat.com>
diff --git a/drivers/mdev/Kconfig b/drivers/mdev/Kconfig
index 4561f2d4178f..cd84d4670552 100644
--- a/drivers/mdev/Kconfig
+++ b/drivers/mdev/Kconfig
@@ -17,3 +17,13 @@ config VFIO_MDEV
          more details.
 
          If you don't know what do here, say N.
+
+config MDEV_VIRTIO
+       tristate "Mediated VIRTIO bus"
+       depends on VIRTIO && MDEV
+       default n
+       help
+         Proivdes a mediated BUS for virtio. It could be used by
+          either kenrel driver or userspace driver.
+
+         If you don't know what do here, say N.
diff --git a/drivers/mdev/Makefile b/drivers/mdev/Makefile
index 0b749e7f8ff4..eb14031c9944 100644
--- a/drivers/mdev/Makefile
+++ b/drivers/mdev/Makefile
@@ -1,5 +1,7 @@
 
 mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o
 mdev_vfio-y := vfio.o
+mdev_virtio-y := virtio.o
 obj-$(CONFIG_MDEV) += mdev.o
 obj-$(CONFIG_VFIO_MDEV) += mdev_vfio.o
+obj-$(CONFIG_MDEV_VIRTIO) += mdev_virtio.o
diff --git a/drivers/mdev/virtio.c b/drivers/mdev/virtio.c
new file mode 100644
index 000000000000..25de329615c4
--- /dev/null
+++ b/drivers/mdev/virtio.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Mediated VIRTIO bus
+ *
+ * Copyright (c) 2019, Red Hat. All rights reserved.
+ *     Author: Jason Wang <jasow...@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/uuid.h>
+#include <linux/device.h>
+#include <linux/mdev.h>
+#include <linux/mdev_virtio.h>
+#include <linux/mod_devicetable.h>
+
+#include "mdev_private.h"
+
+#define DRIVER_VERSION         "0.1"
+#define DRIVER_AUTHOR          "Jason Wang"
+#define DRIVER_DESC            "Mediated VIRTIO bus"
+
+struct bus_type mdev_virtio_bus_type;
+
+struct mdev_virtio_device {
+       struct mdev_device mdev;
+       const struct mdev_virtio_ops *ops;
+       u16 class_id;
+};
+
+#define to_mdev_virtio(mdev) container_of(mdev, \
+                                         struct mdev_virtio_device, mdev)
+#define to_mdev_virtio_drv(mdrv) container_of(mdrv, \
+                                             struct mdev_virtio_driver, drv)
+
+static int mdev_virtio_match(struct device *dev, struct device_driver *drv)
+{
+       unsigned int i;
+       struct mdev_device *mdev = mdev_from_dev(dev, &mdev_virtio_bus_type);
+       struct mdev_virtio_device *mdev_virtio = to_mdev_virtio(mdev);
+       struct mdev_driver *mdrv = to_mdev_driver(drv);
+       struct mdev_virtio_driver *mdrv_virtio = to_mdev_virtio_drv(mdrv);
+       const struct mdev_virtio_class_id *ids = mdrv_virtio->id_table;
+
+       if (!ids)
+               return 0;
+
+       for (i = 0; ids[i].id; i++)
+               if (ids[i].id == mdev_virtio->class_id)
+                       return 1;
+       return 0;
+}
+
+static int mdev_virtio_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct mdev_device *mdev = mdev_from_dev(dev, &mdev_virtio_bus_type);
+       struct mdev_virtio_device *mdev_virtio = to_mdev_virtio(mdev);
+
+       return add_uevent_var(env, "MODALIAS=mdev_virtio:c%02X",
+                             mdev_virtio->class_id);
+}
+
+struct bus_type mdev_virtio_bus_type = {
+       .name           = "mdev_virtio",
+       .probe          = mdev_probe,
+       .remove         = mdev_remove,
+       .match          = mdev_virtio_match,
+       .uevent         = mdev_virtio_uevent,
+};
+EXPORT_SYMBOL(mdev_virtio_bus_type);
+
+void mdev_virtio_set_class_id(struct mdev_device *mdev, u16 class_id)
+{
+       struct mdev_virtio_device *mdev_virtio = to_mdev_virtio(mdev);
+
+       mdev_virtio->class_id = class_id;
+}
+EXPORT_SYMBOL(mdev_virtio_set_class_id);
+
+int mdev_virtio_register_device(struct device *dev,
+                               const struct mdev_parent_ops *ops)
+{
+       return mdev_register_device(dev, ops, &mdev_virtio_bus_type,
+                                   sizeof(struct mdev_virtio_device));
+}
+EXPORT_SYMBOL(mdev_virtio_register_device);
+
+void mdev_virtio_unregister_device(struct device *dev)
+{
+       return mdev_unregister_device(dev);
+}
+EXPORT_SYMBOL(mdev_virtio_unregister_device);
+
+void mdev_virtio_set_ops(struct mdev_device *mdev,
+                        const struct mdev_virtio_ops *ops)
+{
+       struct mdev_virtio_device *mdev_virtio = to_mdev_virtio(mdev);
+
+       mdev_virtio->ops = ops;
+}
+EXPORT_SYMBOL(mdev_virtio_set_ops);
+
+const struct mdev_virtio_ops *mdev_virtio_get_ops(struct mdev_device *mdev)
+{
+       struct mdev_virtio_device *mdev_virtio = to_mdev_virtio(mdev);
+
+       return mdev_virtio->ops;
+}
+EXPORT_SYMBOL(mdev_virtio_get_ops);
+
+static int __init mdev_init(void)
+{
+       return mdev_register_bus(&mdev_virtio_bus_type);
+}
+
+static void __exit mdev_exit(void)
+{
+       mdev_unregister_bus(&mdev_virtio_bus_type);
+}
+
+module_init(mdev_init)
+module_exit(mdev_exit)
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/linux/mdev_virtio.h b/include/linux/mdev_virtio.h
new file mode 100644
index 000000000000..ef2dbb6c383a
--- /dev/null
+++ b/include/linux/mdev_virtio.h
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * VIRTIO Mediated device definition
+ *
+ * Copyright (c) 2019, Red Hat. All rights reserved.
+ *     Author: Jason Wang <jasow...@redhat.com>
+ */
+
+#ifndef VIRTIO_MDEV_H
+#define VIRTIO_MDEV_H
+
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mdev.h>
+
+extern struct bus_type mdev_virtio_bus_type;
+
+struct mdev_virtio_driver {
+       struct mdev_driver drv;
+       const struct mdev_virtio_class_id *id_table;
+};
+
+struct virtio_mdev_callback {
+       irqreturn_t (*callback)(void *data);
+       void *private;
+};
+
+/**
+ * struct mdev_virtio_device_ops - Structure to be registered for each
+ * mdev device to register the device for virtio/vhost drivers.
+ *
+ * The callbacks are mandatory unless explicitly mentioned.
+ *
+ * @set_vq_address:            Set the address of virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ *                             @desc_area: address of desc area
+ *                             @driver_area: address of driver area
+ *                             @device_area: address of device area
+ *                             Returns integer: success (0) or error (< 0)
+ * @set_vq_num:                        Set the size of virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ *                             @num: the size of virtqueue
+ * @kick_vq:                   Kick the virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ * @set_vq_cb:                 Set the interrupt callback function for
+ *                             a virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ *                             @cb: virtio-mdev interrupt callback structure
+ * @set_vq_ready:              Set ready status for a virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ *                             @ready: ready (true) not ready(false)
+ * @get_vq_ready:              Get ready status for a virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ *                             Returns boolean: ready (true) or not (false)
+ * @set_vq_state:              Set the state for a virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ *                             @state: virtqueue state (last_avail_idx)
+ *                             Returns integer: success (0) or error (< 0)
+ * @get_vq_state:              Get the state for a virtqueue
+ *                             @mdev: mediated device
+ *                             @idx: virtqueue index
+ *                             Returns virtqueue state (last_avail_idx)
+ * @get_vq_align:              Get the virtqueue align requirement
+ *                             for the device
+ *                             @mdev: mediated device
+ *                             Returns virtqueue algin requirement
+ * @get_features:              Get virtio features supported by the device
+ *                             @mdev: mediated device
+ *                             Returns the virtio features support by the
+ *                             device
+ * @set_features:              Set virtio features supported by the driver
+ *                             @mdev: mediated device
+ *                             @features: feature support by the driver
+ *                             Returns integer: success (0) or error (< 0)
+ * @set_config_cb:             Set the config interrupt callback
+ *                             @mdev: mediated device
+ *                             @cb: virtio-mdev interrupt callback structure
+ * @get_vq_num_max:            Get the max size of virtqueue
+ *                             @mdev: mediated device
+ *                             Returns u16: max size of virtqueue
+ * @get_device_id:             Get virtio device id
+ *                             @mdev: mediated device
+ *                             Returns u32: virtio device id
+ * @get_vendor_id:             Get id for the vendor that provides this device
+ *                             @mdev: mediated device
+ *                             Returns u32: virtio vendor id
+ * @get_status:                        Get the device status
+ *                             @mdev: mediated device
+ *                             Returns u8: virtio device status
+ * @set_status:                        Set the device status
+ *                             @mdev: mediated device
+ *                             @status: virtio device status
+ * @get_config:                        Read from device specific configuration 
space
+ *                             @mdev: mediated device
+ *                             @offset: offset from the beginning of
+ *                             configuration space
+ *                             @buf: buffer used to read to
+ *                             @len: the length to read from
+ *                             configration space
+ * @set_config:                        Write to device specific configuration 
space
+ *                             @mdev: mediated device
+ *                             @offset: offset from the beginning of
+ *                             configuration space
+ *                             @buf: buffer used to write from
+ *                             @len: the length to write to
+ *                             configration space
+ * @get_generation:            Get device config generaton (optional)
+ *                             @mdev: mediated device
+ *                             Returns u32: device generation
+ */
+struct mdev_virtio_ops {
+       /* Virtqueue ops */
+       int (*set_vq_address)(struct mdev_device *mdev,
+                             u16 idx, u64 desc_area, u64 driver_area,
+                             u64 device_area);
+       void (*set_vq_num)(struct mdev_device *mdev, u16 idx, u32 num);
+       void (*kick_vq)(struct mdev_device *mdev, u16 idx);
+       void (*set_vq_cb)(struct mdev_device *mdev, u16 idx,
+                         struct virtio_mdev_callback *cb);
+       void (*set_vq_ready)(struct mdev_device *mdev, u16 idx, bool ready);
+       bool (*get_vq_ready)(struct mdev_device *mdev, u16 idx);
+       int (*set_vq_state)(struct mdev_device *mdev, u16 idx, u64 state);
+       u64 (*get_vq_state)(struct mdev_device *mdev, u16 idx);
+
+       /* Device ops */
+       u16 (*get_vq_align)(struct mdev_device *mdev);
+       u64 (*get_features)(struct mdev_device *mdev);
+       int (*set_features)(struct mdev_device *mdev, u64 features);
+       void (*set_config_cb)(struct mdev_device *mdev,
+                             struct virtio_mdev_callback *cb);
+       u16 (*get_vq_num_max)(struct mdev_device *mdev);
+       u32 (*get_device_id)(struct mdev_device *mdev);
+       u32 (*get_vendor_id)(struct mdev_device *mdev);
+       u8 (*get_status)(struct mdev_device *mdev);
+       void (*set_status)(struct mdev_device *mdev, u8 status);
+       void (*get_config)(struct mdev_device *mdev, unsigned int offset,
+                          void *buf, unsigned int len);
+       void (*set_config)(struct mdev_device *mdev, unsigned int offset,
+                          const void *buf, unsigned int len);
+       u32 (*get_generation)(struct mdev_device *mdev);
+};
+
+int mdev_virtio_register_device(struct device *dev,
+                               const struct mdev_parent_ops *ops);
+void mdev_virtio_unregister_device(struct device *dev);
+void mdev_virtio_set_ops(struct mdev_device *mdev,
+                        const struct mdev_virtio_ops *ops);
+const struct mdev_virtio_ops *mdev_virtio_get_ops(struct mdev_device *mdev);
+void mdev_virtio_set_class_id(struct mdev_device *mdev, u16 class_id);
+
+static inline struct mdev_device *mdev_virtio_from_dev(struct device *dev)
+{
+       return mdev_from_dev(dev, &mdev_virtio_bus_type);
+}
+
+#endif
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 5714fd35a83c..59006c47ae8e 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -821,4 +821,12 @@ struct wmi_device_id {
        const void *context;
 };
 
+/**
+ * struct mdev_class_id - MDEV VIRTIO device class identifier
+ * @id: Used to identify a specific class of device, e.g vfio-mdev device.
+ */
+struct mdev_virtio_class_id {
+       __u16 id;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/scripts/mod/devicetable-offsets.c 
b/scripts/mod/devicetable-offsets.c
index 054405b90ba4..178fd7c70812 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -231,5 +231,8 @@ int main(void)
        DEVID(wmi_device_id);
        DEVID_FIELD(wmi_device_id, guid_string);
 
+       DEVID(mdev_virtio_class_id);
+       DEVID_FIELD(mdev_virtio_class_id, id);
+
        return 0;
 }
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index c91eba751804..1a9c1f591951 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -1335,6 +1335,17 @@ static int do_wmi_entry(const char *filename, void 
*symval, char *alias)
        return 1;
 }
 
+/* looks like: "mdev_virtio:cN" */
+static int do_mdev_virtio_entry(const char *filename, void *symval, char 
*alias)
+{
+       DEF_FIELD(symval, mdev_virtio_class_id, id);
+
+       sprintf(alias, "mdev_virtio:c%02X", id);
+       add_wildcard(alias);
+       return 1;
+}
+
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
@@ -1407,6 +1418,7 @@ static const struct devtable devtable[] = {
        {"typec", SIZE_typec_device_id, do_typec_entry},
        {"tee", SIZE_tee_client_device_id, do_tee_entry},
        {"wmi", SIZE_wmi_device_id, do_wmi_entry},
+       {"mdev_virtio", SIZE_mdev_virtio_class_id, do_mdev_virtio_entry},
 };
 
 /* Create MODULE_ALIAS() statements.
-- 
2.19.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to