@@ -444,7 +444,8 @@ static void kvmgt_put_vfio_device(void *vgpu)
vfio_device_put(((struct intel_vgpu *)vgpu)->vdev.vfio_device);
}
-static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
+static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev,
+ unsigned int instances)
{
struct intel_vgpu *vgpu = NULL;
struct intel_vgpu_type *type;
@@ -106,7 +106,8 @@ static struct attribute_group *mdev_type_groups[] = {
NULL,
};
-static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
+static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev,
+ unsigned int instances)
{
struct vfio_ccw_private *private =
dev_get_drvdata(mdev_parent_dev(mdev));
@@ -104,12 +104,13 @@ static inline void mdev_put_parent(struct mdev_parent *parent)
}
static int mdev_device_create_ops(struct kobject *kobj,
- struct mdev_device *mdev)
+ struct mdev_device *mdev,
+ unsigned int instances)
{
struct mdev_parent *parent = mdev->parent;
int ret;
- ret = parent->ops->create(kobj, mdev);
+ ret = parent->ops->create(kobj, mdev, instances);
if (ret)
return ret;
@@ -276,7 +277,8 @@ static void mdev_device_release(struct device *dev)
kfree(mdev);
}
-int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
+int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid,
+ unsigned int instances)
{
int ret;
struct mdev_device *mdev, *tmp;
@@ -316,6 +318,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
mdev->dev.bus = &mdev_bus_type;
mdev->dev.release = mdev_device_release;
dev_set_name(&mdev->dev, "%pUl", uuid.b);
+ mdev->type_instances = instances;
ret = device_register(&mdev->dev);
if (ret) {
@@ -323,7 +326,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
goto mdev_fail;
}
- ret = mdev_device_create_ops(kobj, mdev);
+ ret = mdev_device_create_ops(kobj, mdev, instances);
if (ret)
goto create_fail;
@@ -33,6 +33,7 @@ struct mdev_device {
struct kref ref;
struct list_head next;
struct kobject *type_kobj;
+ unsigned int type_instances;
bool active;
};
@@ -52,13 +53,16 @@ struct mdev_type {
#define to_mdev_type(_kobj) \
container_of(_kobj, struct mdev_type, kobj)
+#define MDEV_CREATE_OPT_LEN 32
+
int parent_create_sysfs_files(struct mdev_parent *parent);
void parent_remove_sysfs_files(struct mdev_parent *parent);
int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type);
void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type);
-int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid);
+int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid,
+ unsigned int instances);
int mdev_device_remove(struct device *dev, bool force_remove);
#endif /* MDEV_PRIVATE_H */
@@ -54,11 +54,15 @@ static const struct sysfs_ops mdev_type_sysfs_ops = {
static ssize_t create_store(struct kobject *kobj, struct device *dev,
const char *buf, size_t count)
{
- char *str;
+ char *str, *opt = NULL;
uuid_le uuid;
int ret;
+ unsigned int instances = 1;
- if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
+ if (count < UUID_STRING_LEN)
+ return -EINVAL;
+
+ if (count > UUID_STRING_LEN + 1 + MDEV_CREATE_OPT_LEN)
return -EINVAL;
str = kstrndup(buf, count, GFP_KERNEL);
@@ -66,13 +70,31 @@ static ssize_t create_store(struct kobject *kobj, struct device *dev,
return -ENOMEM;
ret = uuid_le_to_bin(str, &uuid);
- kfree(str);
- if (ret)
+ if (ret) {
+ kfree(str);
return ret;
+ }
- ret = mdev_device_create(kobj, dev, uuid);
- if (ret)
+ if (count > UUID_STRING_LEN + 1) {
+ opt = str + UUID_STRING_LEN;
+ if (*opt++ != ',' ||
+ strncmp(opt, "instances=", 10)) {
+ kfree(str);
+ return -EINVAL;
+ }
+ opt += 10;
+ if (kstrtouint(opt, 10, &instances)) {
+ kfree(str);
+ return -EINVAL;
+ }
+ }
+
+ ret = mdev_device_create(kobj, dev, uuid, instances);
+ if (ret) {
+ kfree(str);
return ret;
+ }
+ kfree(str);
return count;
}
@@ -246,10 +268,18 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t instances_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct mdev_device *mdev = to_mdev_device(dev);
+ return sprintf(buf, "%u\n", mdev->type_instances);
+}
+
static DEVICE_ATTR_WO(remove);
+static DEVICE_ATTR_RO(instances);
static const struct attribute *mdev_device_attrs[] = {
&dev_attr_remove.attr,
+ &dev_attr_instances.attr,
NULL,
};
@@ -70,7 +70,8 @@ struct mdev_parent_ops {
const struct attribute_group **mdev_attr_groups;
struct attribute_group **supported_type_groups;
- int (*create)(struct kobject *kobj, struct mdev_device *mdev);
+ int (*create)(struct kobject *kobj, struct mdev_device *mdev,
+ unsigned int instances);
int (*remove)(struct mdev_device *mdev);
int (*open)(struct mdev_device *mdev);
void (*release)(struct mdev_device *mdev);
@@ -432,7 +432,8 @@ static int mbochs_reset(struct mdev_device *mdev)
return 0;
}
-static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev)
+static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev,
+ unsigned int instances)
{
const struct mbochs_type *type = mbochs_find_type(kobj);
struct device *dev = mdev_dev(mdev);
@@ -226,7 +226,8 @@ static int mdpy_reset(struct mdev_device *mdev)
return 0;
}
-static int mdpy_create(struct kobject *kobj, struct mdev_device *mdev)
+static int mdpy_create(struct kobject *kobj, struct mdev_device *mdev,
+ unsigned int instances)
{
const struct mdpy_type *type = mdpy_find_type(kobj);
struct device *dev = mdev_dev(mdev);
@@ -727,7 +727,8 @@ static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count,
return ret;
}
-int mtty_create(struct kobject *kobj, struct mdev_device *mdev)
+int mtty_create(struct kobject *kobj, struct mdev_device *mdev,
+ unsigned int instances)
{
struct mdev_state *mdev_state;
char name[MTTY_STRING_LEN];
For special mdev type which can aggregate instances for mdev device, this extends mdev create interface by allowing extra "instances=xxx" parameter, which is passed to mdev device model to be able to create arbitrary bundled number of instances for target mdev device. For created mdev device, also create new sysfs attr "instances" to show. For compatibility, current default instances is 1. Cc: Alex Williamson <alex.williamson@redhat.com> Cc: Kirti Wankhede <kwankhede@nvidia.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com> --- drivers/gpu/drm/i915/gvt/kvmgt.c | 3 ++- drivers/s390/cio/vfio_ccw_ops.c | 3 ++- drivers/vfio/mdev/mdev_core.c | 11 ++++++--- drivers/vfio/mdev/mdev_private.h | 6 ++++- drivers/vfio/mdev/mdev_sysfs.c | 42 +++++++++++++++++++++++++++----- include/linux/mdev.h | 3 ++- samples/vfio-mdev/mbochs.c | 3 ++- samples/vfio-mdev/mdpy.c | 3 ++- samples/vfio-mdev/mtty.c | 3 ++- 9 files changed, 60 insertions(+), 17 deletions(-)