Merge tag 'linux-kselftest-kunit-6.1-rc1-2' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-microblaze.git] / drivers / vfio / mdev / mdev_sysfs.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * File attributes for Mediated devices
4  *
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
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,
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
31 static 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
43 static 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
56 static const struct sysfs_ops mdev_type_sysfs_ops = {
57         .show = mdev_type_attr_show,
58         .store = mdev_type_attr_store,
59 };
60
61 static 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 }
87 static MDEV_TYPE_ATTR_WO(create);
88
89 static 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 }
94 static MDEV_TYPE_ATTR_RO(device_api);
95
96 static ssize_t name_show(struct mdev_type *mtype,
97                          struct mdev_type_attribute *attr, char *buf)
98 {
99         return sprintf(buf, "%s\n",
100                 mtype->pretty_name ? mtype->pretty_name : mtype->sysfs_name);
101 }
102
103 static MDEV_TYPE_ATTR_RO(name);
104
105 static 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 }
116 static MDEV_TYPE_ATTR_RO(available_instances);
117
118 static 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 }
124 static MDEV_TYPE_ATTR_RO(description);
125
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,
132         NULL,
133 };
134
135 static 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
144 static struct attribute_group mdev_type_core_group = {
145         .attrs = mdev_types_core_attrs,
146         .is_visible = mdev_types_core_is_visible,
147 };
148
149 static const struct attribute_group *mdev_type_groups[] = {
150         &mdev_type_core_group,
151         NULL,
152 };
153
154 static 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
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,
167 };
168
169 static 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
194 attr_devices_failed:
195         kobject_del(&type->kobj);
196         kobject_put(&type->kobj);
197         return ret;
198 }
199
200 static 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 */
208 void 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
217 int 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
233 out_err:
234         while (--i >= 0)
235                 mdev_type_remove(parent->types[i]);
236         return 0;
237 }
238
239 static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
240                             const char *buf, size_t count)
241 {
242         struct mdev_device *mdev = to_mdev_device(dev);
243         unsigned long val;
244
245         if (kstrtoul(buf, 0, &val) < 0)
246                 return -EINVAL;
247
248         if (val && device_remove_file_self(dev, attr)) {
249                 int ret;
250
251                 ret = mdev_device_remove(mdev);
252                 if (ret)
253                         return ret;
254         }
255
256         return count;
257 }
258
259 static DEVICE_ATTR_WO(remove);
260
261 static struct attribute *mdev_device_attrs[] = {
262         &dev_attr_remove.attr,
263         NULL,
264 };
265
266 static const struct attribute_group mdev_device_group = {
267         .attrs = mdev_device_attrs,
268 };
269
270 const struct attribute_group *mdev_device_groups[] = {
271         &mdev_device_group,
272         NULL
273 };
274
275 int mdev_create_sysfs_files(struct mdev_device *mdev)
276 {
277         struct mdev_type *type = mdev->type;
278         struct kobject *kobj = &mdev->dev.kobj;
279         int ret;
280
281         ret = sysfs_create_link(type->devices_kobj, kobj, dev_name(&mdev->dev));
282         if (ret)
283                 return ret;
284
285         ret = sysfs_create_link(kobj, &type->kobj, "mdev_type");
286         if (ret)
287                 goto type_link_failed;
288         return ret;
289
290 type_link_failed:
291         sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
292         return ret;
293 }
294
295 void mdev_remove_sysfs_files(struct mdev_device *mdev)
296 {
297         struct kobject *kobj = &mdev->dev.kobj;
298
299         sysfs_remove_link(kobj, "mdev_type");
300         sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev));
301 }