brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · e44bb44 Raw
303 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * File attributes for Mediated devices4 *5 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.6 *     Author: Neo Jia <cjia@nvidia.com>7 *             Kirti Wankhede <kwankhede@nvidia.com>8 */9 10#include <linux/sysfs.h>11#include <linux/ctype.h>12#include <linux/slab.h>13#include <linux/mdev.h>14 15#include "mdev_private.h"16 17struct mdev_type_attribute {18	struct attribute attr;19	ssize_t (*show)(struct mdev_type *mtype,20			struct mdev_type_attribute *attr, char *buf);21	ssize_t (*store)(struct mdev_type *mtype,22			 struct mdev_type_attribute *attr, const char *buf,23			 size_t count);24};25 26#define MDEV_TYPE_ATTR_RO(_name) \27	struct mdev_type_attribute mdev_type_attr_##_name = __ATTR_RO(_name)28#define MDEV_TYPE_ATTR_WO(_name) \29	struct mdev_type_attribute mdev_type_attr_##_name = __ATTR_WO(_name)30 31static ssize_t mdev_type_attr_show(struct kobject *kobj,32				     struct attribute *__attr, char *buf)33{34	struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);35	struct mdev_type *type = to_mdev_type(kobj);36	ssize_t ret = -EIO;37 38	if (attr->show)39		ret = attr->show(type, attr, buf);40	return ret;41}42 43static ssize_t mdev_type_attr_store(struct kobject *kobj,44				      struct attribute *__attr,45				      const char *buf, size_t count)46{47	struct mdev_type_attribute *attr = to_mdev_type_attr(__attr);48	struct mdev_type *type = to_mdev_type(kobj);49	ssize_t ret = -EIO;50 51	if (attr->store)52		ret = attr->store(type, attr, buf, count);53	return ret;54}55 56static const struct sysfs_ops mdev_type_sysfs_ops = {57	.show = mdev_type_attr_show,58	.store = mdev_type_attr_store,59};60 61static ssize_t create_store(struct mdev_type *mtype,62			    struct mdev_type_attribute *attr, const char *buf,63			    size_t count)64{65	char *str;66	guid_t uuid;67	int ret;68 69	if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))70		return -EINVAL;71 72	str = kstrndup(buf, count, GFP_KERNEL);73	if (!str)74		return -ENOMEM;75 76	ret = guid_parse(str, &uuid);77	kfree(str);78	if (ret)79		return ret;80 81	ret = mdev_device_create(mtype, &uuid);82	if (ret)83		return ret;84 85	return count;86}87static MDEV_TYPE_ATTR_WO(create);88 89static ssize_t device_api_show(struct mdev_type *mtype,90			       struct mdev_type_attribute *attr, char *buf)91{92	return sysfs_emit(buf, "%s\n", mtype->parent->mdev_driver->device_api);93}94static MDEV_TYPE_ATTR_RO(device_api);95 96static ssize_t name_show(struct mdev_type *mtype,97			 struct mdev_type_attribute *attr, char *buf)98{99	return sysfs_emit(buf, "%s\n",100		mtype->pretty_name ? mtype->pretty_name : mtype->sysfs_name);101}102 103static MDEV_TYPE_ATTR_RO(name);104 105static ssize_t available_instances_show(struct mdev_type *mtype,106					struct mdev_type_attribute *attr,107					char *buf)108{109	struct mdev_driver *drv = mtype->parent->mdev_driver;110 111	if (drv->get_available)112		return sysfs_emit(buf, "%u\n", drv->get_available(mtype));113	return sysfs_emit(buf, "%u\n",114			  atomic_read(&mtype->parent->available_instances));115}116static MDEV_TYPE_ATTR_RO(available_instances);117 118static ssize_t description_show(struct mdev_type *mtype,119				struct mdev_type_attribute *attr,120				char *buf)121{122	return mtype->parent->mdev_driver->show_description(mtype, buf);123}124static MDEV_TYPE_ATTR_RO(description);125 126static struct attribute *mdev_types_core_attrs[] = {127	&mdev_type_attr_create.attr,128	&mdev_type_attr_device_api.attr,129	&mdev_type_attr_name.attr,130	&mdev_type_attr_available_instances.attr,131	&mdev_type_attr_description.attr,132	NULL,133};134 135static umode_t mdev_types_core_is_visible(struct kobject *kobj,136					  struct attribute *attr, int n)137{138	if (attr == &mdev_type_attr_description.attr &&139	    !to_mdev_type(kobj)->parent->mdev_driver->show_description)140		return 0;141	return attr->mode;142}143 144static struct attribute_group mdev_type_core_group = {145	.attrs = mdev_types_core_attrs,146	.is_visible = mdev_types_core_is_visible,147};148 149static const struct attribute_group *mdev_type_groups[] = {150	&mdev_type_core_group,151	NULL,152};153 154static void mdev_type_release(struct kobject *kobj)155{156	struct mdev_type *type = to_mdev_type(kobj);157 158	pr_debug("Releasing group %s\n", kobj->name);159	/* Pairs with the get in add_mdev_supported_type() */160	put_device(type->parent->dev);161}162 163static const struct kobj_type mdev_type_ktype = {164	.sysfs_ops	= &mdev_type_sysfs_ops,165	.release	= mdev_type_release,166	.default_groups	= mdev_type_groups,167};168 169static int mdev_type_add(struct mdev_parent *parent, struct mdev_type *type)170{171	int ret;172 173	type->kobj.kset = parent->mdev_types_kset;174	type->parent = parent;175	/* Pairs with the put in mdev_type_release() */176	get_device(parent->dev);177 178	ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL,179				   "%s-%s", dev_driver_string(parent->dev),180				   type->sysfs_name);181	if (ret) {182		kobject_put(&type->kobj);183		return ret;184	}185 186	type->devices_kobj = kobject_create_and_add("devices", &type->kobj);187	if (!type->devices_kobj) {188		ret = -ENOMEM;189		goto attr_devices_failed;190	}191 192	return 0;193 194attr_devices_failed:195	kobject_del(&type->kobj);196	kobject_put(&type->kobj);197	return ret;198}199 200static void mdev_type_remove(struct mdev_type *type)201{202	kobject_put(type->devices_kobj);203	kobject_del(&type->kobj);204	kobject_put(&type->kobj);205}206 207/* mdev sysfs functions */208void parent_remove_sysfs_files(struct mdev_parent *parent)209{210	int i;211 212	for (i = 0; i < parent->nr_types; i++)213		mdev_type_remove(parent->types[i]);214	kset_unregister(parent->mdev_types_kset);215}216 217int parent_create_sysfs_files(struct mdev_parent *parent)218{219	int ret, i;220 221	parent->mdev_types_kset = kset_create_and_add("mdev_supported_types",222					       NULL, &parent->dev->kobj);223	if (!parent->mdev_types_kset)224		return -ENOMEM;225 226	for (i = 0; i < parent->nr_types; i++) {227		ret = mdev_type_add(parent, parent->types[i]);228		if (ret)229			goto out_err;230	}231	return 0;232 233out_err:234	while (--i >= 0)235		mdev_type_remove(parent->types[i]);236	kset_unregister(parent->mdev_types_kset);237	return ret;238}239 240static ssize_t remove_store(struct device *dev, struct device_attribute *attr,241			    const char *buf, size_t count)242{243	struct mdev_device *mdev = to_mdev_device(dev);244	unsigned long val;245 246	if (kstrtoul(buf, 0, &val) < 0)247		return -EINVAL;248 249	if (val && device_remove_file_self(dev, attr)) {250		int ret;251 252		ret = mdev_device_remove(mdev);253		if (ret)254			return ret;255	}256 257	return count;258}259 260static DEVICE_ATTR_WO(remove);261 262static struct attribute *mdev_device_attrs[] = {263	&dev_attr_remove.attr,264	NULL,265};266 267static const struct attribute_group mdev_device_group = {268	.attrs = mdev_device_attrs,269};270 271const struct attribute_group *mdev_device_groups[] = {272	&mdev_device_group,273	NULL274};275 276int mdev_create_sysfs_files(struct mdev_device *mdev)277{278	struct mdev_type *type = mdev->type;279	struct kobject *kobj = &mdev->dev.kobj;280	int ret;281 282	ret = sysfs_create_link(type->devices_kobj, kobj, dev_name(&mdev->dev));283	if (ret)284		return ret;285 286	ret = sysfs_create_link(kobj, &type->kobj, "mdev_type");287	if (ret)288		goto type_link_failed;289	return ret;290 291type_link_failed:292	sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));293	return ret;294}295 296void mdev_remove_sysfs_files(struct mdev_device *mdev)297{298	struct kobject *kobj = &mdev->dev.kobj;299 300	sysfs_remove_link(kobj, "mdev_type");301	sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));302}303