1 // SPDX-License-Identifier: GPL-2.0-only
3 * File attributes for Mediated devices
5 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
6 * Author: Neo Jia <cjia@nvidia.com>
7 * Kirti Wankhede <kwankhede@nvidia.com>
10 #include <linux/sysfs.h>
11 #include <linux/ctype.h>
12 #include <linux/device.h>
13 #include <linux/slab.h>
14 #include <linux/uuid.h>
15 #include <linux/mdev.h>
17 #include "mdev_private.h"
19 /* Static functions */
21 static ssize_t
mdev_type_attr_show(struct kobject
*kobj
,
22 struct attribute
*__attr
, char *buf
)
24 struct mdev_type_attribute
*attr
= to_mdev_type_attr(__attr
);
25 struct mdev_type
*type
= to_mdev_type(kobj
);
29 ret
= attr
->show(kobj
, type
->parent
->dev
, buf
);
33 static ssize_t
mdev_type_attr_store(struct kobject
*kobj
,
34 struct attribute
*__attr
,
35 const char *buf
, size_t count
)
37 struct mdev_type_attribute
*attr
= to_mdev_type_attr(__attr
);
38 struct mdev_type
*type
= to_mdev_type(kobj
);
42 ret
= attr
->store(&type
->kobj
, type
->parent
->dev
, buf
, count
);
46 static const struct sysfs_ops mdev_type_sysfs_ops
= {
47 .show
= mdev_type_attr_show
,
48 .store
= mdev_type_attr_store
,
51 static ssize_t
create_store(struct kobject
*kobj
, struct device
*dev
,
52 const char *buf
, size_t count
)
58 if ((count
< UUID_STRING_LEN
) || (count
> UUID_STRING_LEN
+ 1))
61 str
= kstrndup(buf
, count
, GFP_KERNEL
);
65 ret
= guid_parse(str
, &uuid
);
70 ret
= mdev_device_create(kobj
, dev
, &uuid
);
77 static MDEV_TYPE_ATTR_WO(create
);
79 static void mdev_type_release(struct kobject
*kobj
)
81 struct mdev_type
*type
= to_mdev_type(kobj
);
83 pr_debug("Releasing group %s\n", kobj
->name
);
87 static struct kobj_type mdev_type_ktype
= {
88 .sysfs_ops
= &mdev_type_sysfs_ops
,
89 .release
= mdev_type_release
,
92 static struct mdev_type
*add_mdev_supported_type(struct mdev_parent
*parent
,
93 struct attribute_group
*group
)
95 struct mdev_type
*type
;
99 pr_err("%s: Type name empty!\n", __func__
);
100 return ERR_PTR(-EINVAL
);
103 type
= kzalloc(sizeof(*type
), GFP_KERNEL
);
105 return ERR_PTR(-ENOMEM
);
107 type
->kobj
.kset
= parent
->mdev_types_kset
;
109 ret
= kobject_init_and_add(&type
->kobj
, &mdev_type_ktype
, NULL
,
110 "%s-%s", dev_driver_string(parent
->dev
),
113 kobject_put(&type
->kobj
);
117 ret
= sysfs_create_file(&type
->kobj
, &mdev_type_attr_create
.attr
);
119 goto attr_create_failed
;
121 type
->devices_kobj
= kobject_create_and_add("devices", &type
->kobj
);
122 if (!type
->devices_kobj
) {
124 goto attr_devices_failed
;
127 ret
= sysfs_create_files(&type
->kobj
,
128 (const struct attribute
**)group
->attrs
);
135 type
->parent
= parent
;
139 kobject_put(type
->devices_kobj
);
141 sysfs_remove_file(&type
->kobj
, &mdev_type_attr_create
.attr
);
143 kobject_del(&type
->kobj
);
144 kobject_put(&type
->kobj
);
148 static void remove_mdev_supported_type(struct mdev_type
*type
)
150 sysfs_remove_files(&type
->kobj
,
151 (const struct attribute
**)type
->group
->attrs
);
152 kobject_put(type
->devices_kobj
);
153 sysfs_remove_file(&type
->kobj
, &mdev_type_attr_create
.attr
);
154 kobject_del(&type
->kobj
);
155 kobject_put(&type
->kobj
);
158 static int add_mdev_supported_type_groups(struct mdev_parent
*parent
)
162 for (i
= 0; parent
->ops
->supported_type_groups
[i
]; i
++) {
163 struct mdev_type
*type
;
165 type
= add_mdev_supported_type(parent
,
166 parent
->ops
->supported_type_groups
[i
]);
168 struct mdev_type
*ltype
, *tmp
;
170 list_for_each_entry_safe(ltype
, tmp
, &parent
->type_list
,
172 list_del(<ype
->next
);
173 remove_mdev_supported_type(ltype
);
175 return PTR_ERR(type
);
177 list_add(&type
->next
, &parent
->type_list
);
182 /* mdev sysfs functions */
183 void parent_remove_sysfs_files(struct mdev_parent
*parent
)
185 struct mdev_type
*type
, *tmp
;
187 list_for_each_entry_safe(type
, tmp
, &parent
->type_list
, next
) {
188 list_del(&type
->next
);
189 remove_mdev_supported_type(type
);
192 sysfs_remove_groups(&parent
->dev
->kobj
, parent
->ops
->dev_attr_groups
);
193 kset_unregister(parent
->mdev_types_kset
);
196 int parent_create_sysfs_files(struct mdev_parent
*parent
)
200 parent
->mdev_types_kset
= kset_create_and_add("mdev_supported_types",
201 NULL
, &parent
->dev
->kobj
);
203 if (!parent
->mdev_types_kset
)
206 INIT_LIST_HEAD(&parent
->type_list
);
208 ret
= sysfs_create_groups(&parent
->dev
->kobj
,
209 parent
->ops
->dev_attr_groups
);
213 ret
= add_mdev_supported_type_groups(parent
);
215 sysfs_remove_groups(&parent
->dev
->kobj
,
216 parent
->ops
->dev_attr_groups
);
221 kset_unregister(parent
->mdev_types_kset
);
225 static ssize_t
remove_store(struct device
*dev
, struct device_attribute
*attr
,
226 const char *buf
, size_t count
)
230 if (kstrtoul(buf
, 0, &val
) < 0)
233 if (val
&& device_remove_file_self(dev
, attr
)) {
236 ret
= mdev_device_remove(dev
);
244 static DEVICE_ATTR_WO(remove
);
246 static const struct attribute
*mdev_device_attrs
[] = {
247 &dev_attr_remove
.attr
,
251 int mdev_create_sysfs_files(struct device
*dev
, struct mdev_type
*type
)
255 ret
= sysfs_create_link(type
->devices_kobj
, &dev
->kobj
, dev_name(dev
));
259 ret
= sysfs_create_link(&dev
->kobj
, &type
->kobj
, "mdev_type");
261 goto type_link_failed
;
263 ret
= sysfs_create_files(&dev
->kobj
, mdev_device_attrs
);
265 goto create_files_failed
;
270 sysfs_remove_link(&dev
->kobj
, "mdev_type");
272 sysfs_remove_link(type
->devices_kobj
, dev_name(dev
));
276 void mdev_remove_sysfs_files(struct device
*dev
, struct mdev_type
*type
)
278 sysfs_remove_files(&dev
->kobj
, mdev_device_attrs
);
279 sysfs_remove_link(&dev
->kobj
, "mdev_type");
280 sysfs_remove_link(type
->devices_kobj
, dev_name(dev
));