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/slab.h>
13 #include <linux/mdev.h>
15 #include "mdev_private.h"
17 struct 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
,
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)
31 static ssize_t
mdev_type_attr_show(struct kobject
*kobj
,
32 struct attribute
*__attr
, char *buf
)
34 struct mdev_type_attribute
*attr
= to_mdev_type_attr(__attr
);
35 struct mdev_type
*type
= to_mdev_type(kobj
);
39 ret
= attr
->show(type
, attr
, buf
);
43 static ssize_t
mdev_type_attr_store(struct kobject
*kobj
,
44 struct attribute
*__attr
,
45 const char *buf
, size_t count
)
47 struct mdev_type_attribute
*attr
= to_mdev_type_attr(__attr
);
48 struct mdev_type
*type
= to_mdev_type(kobj
);
52 ret
= attr
->store(type
, attr
, buf
, count
);
56 static const struct sysfs_ops mdev_type_sysfs_ops
= {
57 .show
= mdev_type_attr_show
,
58 .store
= mdev_type_attr_store
,
61 static ssize_t
create_store(struct mdev_type
*mtype
,
62 struct mdev_type_attribute
*attr
, const char *buf
,
69 if ((count
< UUID_STRING_LEN
) || (count
> UUID_STRING_LEN
+ 1))
72 str
= kstrndup(buf
, count
, GFP_KERNEL
);
76 ret
= guid_parse(str
, &uuid
);
81 ret
= mdev_device_create(mtype
, &uuid
);
87 static MDEV_TYPE_ATTR_WO(create
);
89 static ssize_t
device_api_show(struct mdev_type
*mtype
,
90 struct mdev_type_attribute
*attr
, char *buf
)
92 return sysfs_emit(buf
, "%s\n", mtype
->parent
->mdev_driver
->device_api
);
94 static MDEV_TYPE_ATTR_RO(device_api
);
96 static ssize_t
name_show(struct mdev_type
*mtype
,
97 struct mdev_type_attribute
*attr
, char *buf
)
99 return sysfs_emit(buf
, "%s\n",
100 mtype
->pretty_name
? mtype
->pretty_name
: mtype
->sysfs_name
);
103 static MDEV_TYPE_ATTR_RO(name
);
105 static ssize_t
available_instances_show(struct mdev_type
*mtype
,
106 struct mdev_type_attribute
*attr
,
109 struct mdev_driver
*drv
= mtype
->parent
->mdev_driver
;
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
));
116 static MDEV_TYPE_ATTR_RO(available_instances
);
118 static ssize_t
description_show(struct mdev_type
*mtype
,
119 struct mdev_type_attribute
*attr
,
122 return mtype
->parent
->mdev_driver
->show_description(mtype
, buf
);
124 static MDEV_TYPE_ATTR_RO(description
);
126 static 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
,
135 static umode_t
mdev_types_core_is_visible(struct kobject
*kobj
,
136 struct attribute
*attr
, int n
)
138 if (attr
== &mdev_type_attr_description
.attr
&&
139 !to_mdev_type(kobj
)->parent
->mdev_driver
->show_description
)
144 static struct attribute_group mdev_type_core_group
= {
145 .attrs
= mdev_types_core_attrs
,
146 .is_visible
= mdev_types_core_is_visible
,
149 static const struct attribute_group
*mdev_type_groups
[] = {
150 &mdev_type_core_group
,
154 static void mdev_type_release(struct kobject
*kobj
)
156 struct mdev_type
*type
= to_mdev_type(kobj
);
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
);
163 static struct kobj_type mdev_type_ktype
= {
164 .sysfs_ops
= &mdev_type_sysfs_ops
,
165 .release
= mdev_type_release
,
166 .default_groups
= mdev_type_groups
,
169 static int mdev_type_add(struct mdev_parent
*parent
, struct mdev_type
*type
)
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
);
178 ret
= kobject_init_and_add(&type
->kobj
, &mdev_type_ktype
, NULL
,
179 "%s-%s", dev_driver_string(parent
->dev
),
182 kobject_put(&type
->kobj
);
186 type
->devices_kobj
= kobject_create_and_add("devices", &type
->kobj
);
187 if (!type
->devices_kobj
) {
189 goto attr_devices_failed
;
195 kobject_del(&type
->kobj
);
196 kobject_put(&type
->kobj
);
200 static void mdev_type_remove(struct mdev_type
*type
)
202 kobject_put(type
->devices_kobj
);
203 kobject_del(&type
->kobj
);
204 kobject_put(&type
->kobj
);
207 /* mdev sysfs functions */
208 void parent_remove_sysfs_files(struct mdev_parent
*parent
)
212 for (i
= 0; i
< parent
->nr_types
; i
++)
213 mdev_type_remove(parent
->types
[i
]);
214 kset_unregister(parent
->mdev_types_kset
);
217 int parent_create_sysfs_files(struct mdev_parent
*parent
)
221 parent
->mdev_types_kset
= kset_create_and_add("mdev_supported_types",
222 NULL
, &parent
->dev
->kobj
);
223 if (!parent
->mdev_types_kset
)
226 for (i
= 0; i
< parent
->nr_types
; i
++) {
227 ret
= mdev_type_add(parent
, parent
->types
[i
]);
235 mdev_type_remove(parent
->types
[i
]);
236 kset_unregister(parent
->mdev_types_kset
);
240 static ssize_t
remove_store(struct device
*dev
, struct device_attribute
*attr
,
241 const char *buf
, size_t count
)
243 struct mdev_device
*mdev
= to_mdev_device(dev
);
246 if (kstrtoul(buf
, 0, &val
) < 0)
249 if (val
&& device_remove_file_self(dev
, attr
)) {
252 ret
= mdev_device_remove(mdev
);
260 static DEVICE_ATTR_WO(remove
);
262 static struct attribute
*mdev_device_attrs
[] = {
263 &dev_attr_remove
.attr
,
267 static const struct attribute_group mdev_device_group
= {
268 .attrs
= mdev_device_attrs
,
271 const struct attribute_group
*mdev_device_groups
[] = {
276 int mdev_create_sysfs_files(struct mdev_device
*mdev
)
278 struct mdev_type
*type
= mdev
->type
;
279 struct kobject
*kobj
= &mdev
->dev
.kobj
;
282 ret
= sysfs_create_link(type
->devices_kobj
, kobj
, dev_name(&mdev
->dev
));
286 ret
= sysfs_create_link(kobj
, &type
->kobj
, "mdev_type");
288 goto type_link_failed
;
292 sysfs_remove_link(mdev
->type
->devices_kobj
, dev_name(&mdev
->dev
));
296 void mdev_remove_sysfs_files(struct mdev_device
*mdev
)
298 struct kobject
*kobj
= &mdev
->dev
.kobj
;
300 sysfs_remove_link(kobj
, "mdev_type");
301 sysfs_remove_link(mdev
->type
->devices_kobj
, dev_name(&mdev
->dev
));