2019-06-04 16:11:33 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2016-11-17 04:46:13 +08:00
|
|
|
/*
|
|
|
|
* File attributes for Mediated devices
|
|
|
|
*
|
|
|
|
* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
|
|
|
|
* Author: Neo Jia <cjia@nvidia.com>
|
|
|
|
* Kirti Wankhede <kwankhede@nvidia.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/sysfs.h>
|
|
|
|
#include <linux/ctype.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/mdev.h>
|
|
|
|
|
|
|
|
#include "mdev_private.h"
|
|
|
|
|
2022-09-23 17:26:51 +08:00
|
|
|
struct mdev_type_attribute {
|
|
|
|
struct attribute attr;
|
|
|
|
ssize_t (*show)(struct mdev_type *mtype,
|
|
|
|
struct mdev_type_attribute *attr, char *buf);
|
|
|
|
ssize_t (*store)(struct mdev_type *mtype,
|
|
|
|
struct mdev_type_attribute *attr, const char *buf,
|
|
|
|
size_t count);
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MDEV_TYPE_ATTR_RO(_name) \
|
|
|
|
struct mdev_type_attribute mdev_type_attr_##_name = __ATTR_RO(_name)
|
|
|
|
#define MDEV_TYPE_ATTR_WO(_name) \
|
|
|
|
struct mdev_type_attribute mdev_type_attr_##_name = __ATTR_WO(_name)
|
2016-11-17 04:46:13 +08:00
|
|
|
|
|
|
|
static ssize_t mdev_type_attr_show(struct kobject *kobj,
|
|
|
|
struct attribute *__attr, char *buf)
|
|
|
|
{
|
|
|
|
struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
|
|
|
|
struct mdev_type *type = to_mdev_type(kobj);
|
|
|
|
ssize_t ret = -EIO;
|
|
|
|
|
|
|
|
if (attr->show)
|
vfio/mdev: Correct the function signatures for the mdev_type_attributes
The driver core standard is to pass in the properly typed object, the
properly typed attribute and the buffer data. It stems from the root
kobject method:
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,..)
Each subclass of kobject should provide their own function with the same
signature but more specific types, eg struct device uses:
ssize_t (*show)(struct device *dev, struct device_attribute *attr,..)
In this case the existing signature is:
ssize_t (*show)(struct kobject *kobj, struct device *dev,..)
Where kobj is a 'struct mdev_type *' and dev is 'mdev_type->parent->dev'.
Change the mdev_type related sysfs attribute functions to:
ssize_t (*show)(struct mdev_type *mtype, struct mdev_type_attribute *attr,..)
In order to restore type safety and match the driver core standard
There are no current users of 'attr', but if it is ever needed it would be
hard to add in retroactively, so do it now.
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Message-Id: <18-v2-d36939638fc6+d54-vfio2_jgg@nvidia.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
2021-04-07 03:40:41 +08:00
|
|
|
ret = attr->show(type, attr, buf);
|
2016-11-17 04:46:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t mdev_type_attr_store(struct kobject *kobj,
|
|
|
|
struct attribute *__attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
|
|
|
struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);
|
|
|
|
struct mdev_type *type = to_mdev_type(kobj);
|
|
|
|
ssize_t ret = -EIO;
|
|
|
|
|
|
|
|
if (attr->store)
|
vfio/mdev: Correct the function signatures for the mdev_type_attributes
The driver core standard is to pass in the properly typed object, the
properly typed attribute and the buffer data. It stems from the root
kobject method:
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,..)
Each subclass of kobject should provide their own function with the same
signature but more specific types, eg struct device uses:
ssize_t (*show)(struct device *dev, struct device_attribute *attr,..)
In this case the existing signature is:
ssize_t (*show)(struct kobject *kobj, struct device *dev,..)
Where kobj is a 'struct mdev_type *' and dev is 'mdev_type->parent->dev'.
Change the mdev_type related sysfs attribute functions to:
ssize_t (*show)(struct mdev_type *mtype, struct mdev_type_attribute *attr,..)
In order to restore type safety and match the driver core standard
There are no current users of 'attr', but if it is ever needed it would be
hard to add in retroactively, so do it now.
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Message-Id: <18-v2-d36939638fc6+d54-vfio2_jgg@nvidia.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
2021-04-07 03:40:41 +08:00
|
|
|
ret = attr->store(type, attr, buf, count);
|
2016-11-17 04:46:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct sysfs_ops mdev_type_sysfs_ops = {
|
|
|
|
.show = mdev_type_attr_show,
|
|
|
|
.store = mdev_type_attr_store,
|
|
|
|
};
|
|
|
|
|
vfio/mdev: Correct the function signatures for the mdev_type_attributes
The driver core standard is to pass in the properly typed object, the
properly typed attribute and the buffer data. It stems from the root
kobject method:
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,..)
Each subclass of kobject should provide their own function with the same
signature but more specific types, eg struct device uses:
ssize_t (*show)(struct device *dev, struct device_attribute *attr,..)
In this case the existing signature is:
ssize_t (*show)(struct kobject *kobj, struct device *dev,..)
Where kobj is a 'struct mdev_type *' and dev is 'mdev_type->parent->dev'.
Change the mdev_type related sysfs attribute functions to:
ssize_t (*show)(struct mdev_type *mtype, struct mdev_type_attribute *attr,..)
In order to restore type safety and match the driver core standard
There are no current users of 'attr', but if it is ever needed it would be
hard to add in retroactively, so do it now.
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Message-Id: <18-v2-d36939638fc6+d54-vfio2_jgg@nvidia.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
2021-04-07 03:40:41 +08:00
|
|
|
static ssize_t create_store(struct mdev_type *mtype,
|
|
|
|
struct mdev_type_attribute *attr, const char *buf,
|
|
|
|
size_t count)
|
2016-11-17 04:46:13 +08:00
|
|
|
{
|
|
|
|
char *str;
|
2019-01-11 03:00:27 +08:00
|
|
|
guid_t uuid;
|
2016-11-17 04:46:13 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
str = kstrndup(buf, count, GFP_KERNEL);
|
|
|
|
if (!str)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-01-11 03:00:27 +08:00
|
|
|
ret = guid_parse(str, &uuid);
|
2016-11-17 04:46:13 +08:00
|
|
|
kfree(str);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
vfio/mdev: Correct the function signatures for the mdev_type_attributes
The driver core standard is to pass in the properly typed object, the
properly typed attribute and the buffer data. It stems from the root
kobject method:
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,..)
Each subclass of kobject should provide their own function with the same
signature but more specific types, eg struct device uses:
ssize_t (*show)(struct device *dev, struct device_attribute *attr,..)
In this case the existing signature is:
ssize_t (*show)(struct kobject *kobj, struct device *dev,..)
Where kobj is a 'struct mdev_type *' and dev is 'mdev_type->parent->dev'.
Change the mdev_type related sysfs attribute functions to:
ssize_t (*show)(struct mdev_type *mtype, struct mdev_type_attribute *attr,..)
In order to restore type safety and match the driver core standard
There are no current users of 'attr', but if it is ever needed it would be
hard to add in retroactively, so do it now.
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Message-Id: <18-v2-d36939638fc6+d54-vfio2_jgg@nvidia.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
2021-04-07 03:40:41 +08:00
|
|
|
ret = mdev_device_create(mtype, &uuid);
|
2016-11-17 04:46:13 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
2019-12-18 20:31:19 +08:00
|
|
|
static MDEV_TYPE_ATTR_WO(create);
|
2016-11-17 04:46:13 +08:00
|
|
|
|
2022-09-23 17:26:48 +08:00
|
|
|
static ssize_t device_api_show(struct mdev_type *mtype,
|
|
|
|
struct mdev_type_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
return sysfs_emit(buf, "%s\n", mtype->parent->mdev_driver->device_api);
|
|
|
|
}
|
|
|
|
static MDEV_TYPE_ATTR_RO(device_api);
|
|
|
|
|
2022-09-23 17:26:49 +08:00
|
|
|
static ssize_t name_show(struct mdev_type *mtype,
|
|
|
|
struct mdev_type_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
return sprintf(buf, "%s\n",
|
|
|
|
mtype->pretty_name ? mtype->pretty_name : mtype->sysfs_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MDEV_TYPE_ATTR_RO(name);
|
|
|
|
|
2022-09-23 17:26:50 +08:00
|
|
|
static ssize_t available_instances_show(struct mdev_type *mtype,
|
|
|
|
struct mdev_type_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct mdev_driver *drv = mtype->parent->mdev_driver;
|
|
|
|
|
|
|
|
return sysfs_emit(buf, "%u\n", drv->get_available(mtype));
|
|
|
|
}
|
|
|
|
static MDEV_TYPE_ATTR_RO(available_instances);
|
|
|
|
|
2022-09-23 17:26:51 +08:00
|
|
|
static ssize_t description_show(struct mdev_type *mtype,
|
|
|
|
struct mdev_type_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
return mtype->parent->mdev_driver->show_description(mtype, buf);
|
|
|
|
}
|
|
|
|
static MDEV_TYPE_ATTR_RO(description);
|
|
|
|
|
2022-09-23 17:26:48 +08:00
|
|
|
static struct attribute *mdev_types_core_attrs[] = {
|
|
|
|
&mdev_type_attr_create.attr,
|
|
|
|
&mdev_type_attr_device_api.attr,
|
2022-09-23 17:26:49 +08:00
|
|
|
&mdev_type_attr_name.attr,
|
2022-09-23 17:26:50 +08:00
|
|
|
&mdev_type_attr_available_instances.attr,
|
2022-09-23 17:26:51 +08:00
|
|
|
&mdev_type_attr_description.attr,
|
2022-09-23 17:26:48 +08:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2022-09-23 17:26:51 +08:00
|
|
|
static umode_t mdev_types_core_is_visible(struct kobject *kobj,
|
|
|
|
struct attribute *attr, int n)
|
|
|
|
{
|
|
|
|
if (attr == &mdev_type_attr_description.attr &&
|
|
|
|
!to_mdev_type(kobj)->parent->mdev_driver->show_description)
|
|
|
|
return 0;
|
|
|
|
return attr->mode;
|
|
|
|
}
|
|
|
|
|
2022-09-23 17:26:48 +08:00
|
|
|
static struct attribute_group mdev_type_core_group = {
|
|
|
|
.attrs = mdev_types_core_attrs,
|
2022-09-23 17:26:51 +08:00
|
|
|
.is_visible = mdev_types_core_is_visible,
|
2022-09-23 17:26:48 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group *mdev_type_groups[] = {
|
|
|
|
&mdev_type_core_group,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2016-11-17 04:46:13 +08:00
|
|
|
static void mdev_type_release(struct kobject *kobj)
|
|
|
|
{
|
|
|
|
struct mdev_type *type = to_mdev_type(kobj);
|
|
|
|
|
|
|
|
pr_debug("Releasing group %s\n", kobj->name);
|
2021-04-07 03:40:30 +08:00
|
|
|
/* Pairs with the get in add_mdev_supported_type() */
|
2022-09-23 17:26:42 +08:00
|
|
|
put_device(type->parent->dev);
|
2016-11-17 04:46:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct kobj_type mdev_type_ktype = {
|
2022-09-23 17:26:48 +08:00
|
|
|
.sysfs_ops = &mdev_type_sysfs_ops,
|
|
|
|
.release = mdev_type_release,
|
|
|
|
.default_groups = mdev_type_groups,
|
2016-11-17 04:46:13 +08:00
|
|
|
};
|
|
|
|
|
2022-09-23 17:26:43 +08:00
|
|
|
static int mdev_type_add(struct mdev_parent *parent, struct mdev_type *type)
|
2016-11-17 04:46:13 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
type->kobj.kset = parent->mdev_types_kset;
|
2021-04-07 03:40:25 +08:00
|
|
|
type->parent = parent;
|
2021-04-07 03:40:30 +08:00
|
|
|
/* Pairs with the put in mdev_type_release() */
|
2022-09-23 17:26:42 +08:00
|
|
|
get_device(parent->dev);
|
2016-11-17 04:46:13 +08:00
|
|
|
|
|
|
|
ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,
|
|
|
|
"%s-%s", dev_driver_string(parent->dev),
|
2022-09-23 17:26:43 +08:00
|
|
|
type->sysfs_name);
|
2016-11-17 04:46:13 +08:00
|
|
|
if (ret) {
|
2020-05-28 10:01:09 +08:00
|
|
|
kobject_put(&type->kobj);
|
2022-09-23 17:26:43 +08:00
|
|
|
return ret;
|
2016-11-17 04:46:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type->devices_kobj = kobject_create_and_add("devices", &type->kobj);
|
|
|
|
if (!type->devices_kobj) {
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto attr_devices_failed;
|
|
|
|
}
|
|
|
|
|
2022-09-23 17:26:43 +08:00
|
|
|
return 0;
|
2016-11-17 04:46:13 +08:00
|
|
|
|
|
|
|
attr_devices_failed:
|
|
|
|
kobject_del(&type->kobj);
|
|
|
|
kobject_put(&type->kobj);
|
2022-09-23 17:26:43 +08:00
|
|
|
return ret;
|
2016-11-17 04:46:13 +08:00
|
|
|
}
|
|
|
|
|
2022-09-23 17:26:43 +08:00
|
|
|
static void mdev_type_remove(struct mdev_type *type)
|
2016-11-17 04:46:13 +08:00
|
|
|
{
|
|
|
|
kobject_put(type->devices_kobj);
|
|
|
|
kobject_del(&type->kobj);
|
|
|
|
kobject_put(&type->kobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mdev sysfs functions */
|
2016-12-30 23:13:38 +08:00
|
|
|
void parent_remove_sysfs_files(struct mdev_parent *parent)
|
2016-11-17 04:46:13 +08:00
|
|
|
{
|
2022-09-23 17:26:43 +08:00
|
|
|
int i;
|
2016-11-17 04:46:13 +08:00
|
|
|
|
2022-09-23 17:26:43 +08:00
|
|
|
for (i = 0; i < parent->nr_types; i++)
|
|
|
|
mdev_type_remove(parent->types[i]);
|
2016-11-17 04:46:13 +08:00
|
|
|
kset_unregister(parent->mdev_types_kset);
|
|
|
|
}
|
|
|
|
|
2016-12-30 23:13:38 +08:00
|
|
|
int parent_create_sysfs_files(struct mdev_parent *parent)
|
2016-11-17 04:46:13 +08:00
|
|
|
{
|
2022-09-23 17:26:43 +08:00
|
|
|
int ret, i;
|
2016-11-17 04:46:13 +08:00
|
|
|
|
|
|
|
parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",
|
|
|
|
NULL, &parent->dev->kobj);
|
|
|
|
if (!parent->mdev_types_kset)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-09-23 17:26:43 +08:00
|
|
|
for (i = 0; i < parent->nr_types; i++) {
|
|
|
|
ret = mdev_type_add(parent, parent->types[i]);
|
|
|
|
if (ret)
|
|
|
|
goto out_err;
|
|
|
|
}
|
2022-04-11 22:14:00 +08:00
|
|
|
return 0;
|
2016-11-17 04:46:13 +08:00
|
|
|
|
2022-09-23 17:26:43 +08:00
|
|
|
out_err:
|
|
|
|
while (--i >= 0)
|
|
|
|
mdev_type_remove(parent->types[i]);
|
|
|
|
return 0;
|
2016-11-17 04:46:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
|
|
|
|
const char *buf, size_t count)
|
|
|
|
{
|
2021-04-07 03:40:26 +08:00
|
|
|
struct mdev_device *mdev = to_mdev_device(dev);
|
2016-11-17 04:46:13 +08:00
|
|
|
unsigned long val;
|
|
|
|
|
|
|
|
if (kstrtoul(buf, 0, &val) < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (val && device_remove_file_self(dev, attr)) {
|
|
|
|
int ret;
|
|
|
|
|
2021-04-07 03:40:26 +08:00
|
|
|
ret = mdev_device_remove(mdev);
|
2019-06-07 00:52:33 +08:00
|
|
|
if (ret)
|
2016-11-17 04:46:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static DEVICE_ATTR_WO(remove);
|
|
|
|
|
2022-04-11 22:14:02 +08:00
|
|
|
static struct attribute *mdev_device_attrs[] = {
|
2016-11-17 04:46:13 +08:00
|
|
|
&dev_attr_remove.attr,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2022-04-11 22:14:02 +08:00
|
|
|
static const struct attribute_group mdev_device_group = {
|
|
|
|
.attrs = mdev_device_attrs,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct attribute_group *mdev_device_groups[] = {
|
|
|
|
&mdev_device_group,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2021-04-07 03:40:28 +08:00
|
|
|
int mdev_create_sysfs_files(struct mdev_device *mdev)
|
2016-11-17 04:46:13 +08:00
|
|
|
{
|
2021-04-07 03:40:28 +08:00
|
|
|
struct mdev_type *type = mdev->type;
|
2021-04-07 03:40:26 +08:00
|
|
|
struct kobject *kobj = &mdev->dev.kobj;
|
2016-11-17 04:46:13 +08:00
|
|
|
int ret;
|
|
|
|
|
2021-04-07 03:40:26 +08:00
|
|
|
ret = sysfs_create_link(type->devices_kobj, kobj, dev_name(&mdev->dev));
|
2016-11-17 04:46:13 +08:00
|
|
|
if (ret)
|
2018-05-19 01:40:33 +08:00
|
|
|
return ret;
|
2016-11-17 04:46:13 +08:00
|
|
|
|
2021-04-07 03:40:26 +08:00
|
|
|
ret = sysfs_create_link(kobj, &type->kobj, "mdev_type");
|
2016-11-17 04:46:13 +08:00
|
|
|
if (ret)
|
|
|
|
goto type_link_failed;
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
type_link_failed:
|
2021-04-07 03:40:28 +08:00
|
|
|
sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
|
2016-11-17 04:46:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-04-07 03:40:28 +08:00
|
|
|
void mdev_remove_sysfs_files(struct mdev_device *mdev)
|
2016-11-17 04:46:13 +08:00
|
|
|
{
|
2021-04-07 03:40:26 +08:00
|
|
|
struct kobject *kobj = &mdev->dev.kobj;
|
|
|
|
|
|
|
|
sysfs_remove_link(kobj, "mdev_type");
|
2021-04-07 03:40:28 +08:00
|
|
|
sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
|
2016-11-17 04:46:13 +08:00
|
|
|
}
|