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 sysfs_emit(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 } 302