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 return sysfs_emit(buf, "%u\n", drv->get_available(mtype)); 112 } 113 static MDEV_TYPE_ATTR_RO(available_instances); 114 115 static ssize_t description_show(struct mdev_type *mtype, 116 struct mdev_type_attribute *attr, 117 char *buf) 118 { 119 return mtype->parent->mdev_driver->show_description(mtype, buf); 120 } 121 static MDEV_TYPE_ATTR_RO(description); 122 123 static struct attribute *mdev_types_core_attrs[] = { 124 &mdev_type_attr_create.attr, 125 &mdev_type_attr_device_api.attr, 126 &mdev_type_attr_name.attr, 127 &mdev_type_attr_available_instances.attr, 128 &mdev_type_attr_description.attr, 129 NULL, 130 }; 131 132 static umode_t mdev_types_core_is_visible(struct kobject *kobj, 133 struct attribute *attr, int n) 134 { 135 if (attr == &mdev_type_attr_description.attr && 136 !to_mdev_type(kobj)->parent->mdev_driver->show_description) 137 return 0; 138 return attr->mode; 139 } 140 141 static struct attribute_group mdev_type_core_group = { 142 .attrs = mdev_types_core_attrs, 143 .is_visible = mdev_types_core_is_visible, 144 }; 145 146 static const struct attribute_group *mdev_type_groups[] = { 147 &mdev_type_core_group, 148 NULL, 149 }; 150 151 static void mdev_type_release(struct kobject *kobj) 152 { 153 struct mdev_type *type = to_mdev_type(kobj); 154 155 pr_debug("Releasing group %s\n", kobj->name); 156 /* Pairs with the get in add_mdev_supported_type() */ 157 put_device(type->parent->dev); 158 } 159 160 static struct kobj_type mdev_type_ktype = { 161 .sysfs_ops = &mdev_type_sysfs_ops, 162 .release = mdev_type_release, 163 .default_groups = mdev_type_groups, 164 }; 165 166 static int mdev_type_add(struct mdev_parent *parent, struct mdev_type *type) 167 { 168 int ret; 169 170 type->kobj.kset = parent->mdev_types_kset; 171 type->parent = parent; 172 /* Pairs with the put in mdev_type_release() */ 173 get_device(parent->dev); 174 175 ret = kobject_init_and_add(&type->kobj, &mdev_type_ktype, NULL, 176 "%s-%s", dev_driver_string(parent->dev), 177 type->sysfs_name); 178 if (ret) { 179 kobject_put(&type->kobj); 180 return ret; 181 } 182 183 type->devices_kobj = kobject_create_and_add("devices", &type->kobj); 184 if (!type->devices_kobj) { 185 ret = -ENOMEM; 186 goto attr_devices_failed; 187 } 188 189 return 0; 190 191 attr_devices_failed: 192 kobject_del(&type->kobj); 193 kobject_put(&type->kobj); 194 return ret; 195 } 196 197 static void mdev_type_remove(struct mdev_type *type) 198 { 199 kobject_put(type->devices_kobj); 200 kobject_del(&type->kobj); 201 kobject_put(&type->kobj); 202 } 203 204 /* mdev sysfs functions */ 205 void parent_remove_sysfs_files(struct mdev_parent *parent) 206 { 207 int i; 208 209 for (i = 0; i < parent->nr_types; i++) 210 mdev_type_remove(parent->types[i]); 211 kset_unregister(parent->mdev_types_kset); 212 } 213 214 int parent_create_sysfs_files(struct mdev_parent *parent) 215 { 216 int ret, i; 217 218 parent->mdev_types_kset = kset_create_and_add("mdev_supported_types", 219 NULL, &parent->dev->kobj); 220 if (!parent->mdev_types_kset) 221 return -ENOMEM; 222 223 for (i = 0; i < parent->nr_types; i++) { 224 ret = mdev_type_add(parent, parent->types[i]); 225 if (ret) 226 goto out_err; 227 } 228 return 0; 229 230 out_err: 231 while (--i >= 0) 232 mdev_type_remove(parent->types[i]); 233 return 0; 234 } 235 236 static ssize_t remove_store(struct device *dev, struct device_attribute *attr, 237 const char *buf, size_t count) 238 { 239 struct mdev_device *mdev = to_mdev_device(dev); 240 unsigned long val; 241 242 if (kstrtoul(buf, 0, &val) < 0) 243 return -EINVAL; 244 245 if (val && device_remove_file_self(dev, attr)) { 246 int ret; 247 248 ret = mdev_device_remove(mdev); 249 if (ret) 250 return ret; 251 } 252 253 return count; 254 } 255 256 static DEVICE_ATTR_WO(remove); 257 258 static struct attribute *mdev_device_attrs[] = { 259 &dev_attr_remove.attr, 260 NULL, 261 }; 262 263 static const struct attribute_group mdev_device_group = { 264 .attrs = mdev_device_attrs, 265 }; 266 267 const struct attribute_group *mdev_device_groups[] = { 268 &mdev_device_group, 269 NULL 270 }; 271 272 int mdev_create_sysfs_files(struct mdev_device *mdev) 273 { 274 struct mdev_type *type = mdev->type; 275 struct kobject *kobj = &mdev->dev.kobj; 276 int ret; 277 278 ret = sysfs_create_link(type->devices_kobj, kobj, dev_name(&mdev->dev)); 279 if (ret) 280 return ret; 281 282 ret = sysfs_create_link(kobj, &type->kobj, "mdev_type"); 283 if (ret) 284 goto type_link_failed; 285 return ret; 286 287 type_link_failed: 288 sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev)); 289 return ret; 290 } 291 292 void mdev_remove_sysfs_files(struct mdev_device *mdev) 293 { 294 struct kobject *kobj = &mdev->dev.kobj; 295 296 sysfs_remove_link(kobj, "mdev_type"); 297 sysfs_remove_link(mdev->type->devices_kobj, dev_name(&mdev->dev)); 298 } 299