root/drivers/vfio/mdev/mdev_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mdev_parent_dev
  2. mdev_get_drvdata
  3. mdev_set_drvdata
  4. mdev_dev
  5. mdev_from_dev
  6. mdev_uuid
  7. __find_parent_device
  8. mdev_release_parent
  9. mdev_get_parent
  10. mdev_put_parent
  11. mdev_device_remove_common
  12. mdev_device_remove_cb
  13. mdev_register_device
  14. mdev_unregister_device
  15. mdev_device_free
  16. mdev_device_release
  17. mdev_device_create
  18. mdev_device_remove
  19. mdev_set_iommu_device
  20. mdev_get_iommu_device
  21. mdev_init
  22. mdev_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Mediated device Core Driver
   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/module.h>
  11 #include <linux/device.h>
  12 #include <linux/slab.h>
  13 #include <linux/uuid.h>
  14 #include <linux/sysfs.h>
  15 #include <linux/mdev.h>
  16 
  17 #include "mdev_private.h"
  18 
  19 #define DRIVER_VERSION          "0.1"
  20 #define DRIVER_AUTHOR           "NVIDIA Corporation"
  21 #define DRIVER_DESC             "Mediated device Core Driver"
  22 
  23 static LIST_HEAD(parent_list);
  24 static DEFINE_MUTEX(parent_list_lock);
  25 static struct class_compat *mdev_bus_compat_class;
  26 
  27 static LIST_HEAD(mdev_list);
  28 static DEFINE_MUTEX(mdev_list_lock);
  29 
  30 struct device *mdev_parent_dev(struct mdev_device *mdev)
  31 {
  32         return mdev->parent->dev;
  33 }
  34 EXPORT_SYMBOL(mdev_parent_dev);
  35 
  36 void *mdev_get_drvdata(struct mdev_device *mdev)
  37 {
  38         return mdev->driver_data;
  39 }
  40 EXPORT_SYMBOL(mdev_get_drvdata);
  41 
  42 void mdev_set_drvdata(struct mdev_device *mdev, void *data)
  43 {
  44         mdev->driver_data = data;
  45 }
  46 EXPORT_SYMBOL(mdev_set_drvdata);
  47 
  48 struct device *mdev_dev(struct mdev_device *mdev)
  49 {
  50         return &mdev->dev;
  51 }
  52 EXPORT_SYMBOL(mdev_dev);
  53 
  54 struct mdev_device *mdev_from_dev(struct device *dev)
  55 {
  56         return dev_is_mdev(dev) ? to_mdev_device(dev) : NULL;
  57 }
  58 EXPORT_SYMBOL(mdev_from_dev);
  59 
  60 const guid_t *mdev_uuid(struct mdev_device *mdev)
  61 {
  62         return &mdev->uuid;
  63 }
  64 EXPORT_SYMBOL(mdev_uuid);
  65 
  66 /* Should be called holding parent_list_lock */
  67 static struct mdev_parent *__find_parent_device(struct device *dev)
  68 {
  69         struct mdev_parent *parent;
  70 
  71         list_for_each_entry(parent, &parent_list, next) {
  72                 if (parent->dev == dev)
  73                         return parent;
  74         }
  75         return NULL;
  76 }
  77 
  78 static void mdev_release_parent(struct kref *kref)
  79 {
  80         struct mdev_parent *parent = container_of(kref, struct mdev_parent,
  81                                                   ref);
  82         struct device *dev = parent->dev;
  83 
  84         kfree(parent);
  85         put_device(dev);
  86 }
  87 
  88 static struct mdev_parent *mdev_get_parent(struct mdev_parent *parent)
  89 {
  90         if (parent)
  91                 kref_get(&parent->ref);
  92 
  93         return parent;
  94 }
  95 
  96 static void mdev_put_parent(struct mdev_parent *parent)
  97 {
  98         if (parent)
  99                 kref_put(&parent->ref, mdev_release_parent);
 100 }
 101 
 102 /* Caller must hold parent unreg_sem read or write lock */
 103 static void mdev_device_remove_common(struct mdev_device *mdev)
 104 {
 105         struct mdev_parent *parent;
 106         struct mdev_type *type;
 107         int ret;
 108 
 109         type = to_mdev_type(mdev->type_kobj);
 110         mdev_remove_sysfs_files(&mdev->dev, type);
 111         device_del(&mdev->dev);
 112         parent = mdev->parent;
 113         lockdep_assert_held(&parent->unreg_sem);
 114         ret = parent->ops->remove(mdev);
 115         if (ret)
 116                 dev_err(&mdev->dev, "Remove failed: err=%d\n", ret);
 117 
 118         /* Balances with device_initialize() */
 119         put_device(&mdev->dev);
 120         mdev_put_parent(parent);
 121 }
 122 
 123 static int mdev_device_remove_cb(struct device *dev, void *data)
 124 {
 125         if (dev_is_mdev(dev)) {
 126                 struct mdev_device *mdev;
 127 
 128                 mdev = to_mdev_device(dev);
 129                 mdev_device_remove_common(mdev);
 130         }
 131         return 0;
 132 }
 133 
 134 /*
 135  * mdev_register_device : Register a device
 136  * @dev: device structure representing parent device.
 137  * @ops: Parent device operation structure to be registered.
 138  *
 139  * Add device to list of registered parent devices.
 140  * Returns a negative value on error, otherwise 0.
 141  */
 142 int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
 143 {
 144         int ret;
 145         struct mdev_parent *parent;
 146         char *env_string = "MDEV_STATE=registered";
 147         char *envp[] = { env_string, NULL };
 148 
 149         /* check for mandatory ops */
 150         if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
 151                 return -EINVAL;
 152 
 153         dev = get_device(dev);
 154         if (!dev)
 155                 return -EINVAL;
 156 
 157         mutex_lock(&parent_list_lock);
 158 
 159         /* Check for duplicate */
 160         parent = __find_parent_device(dev);
 161         if (parent) {
 162                 parent = NULL;
 163                 ret = -EEXIST;
 164                 goto add_dev_err;
 165         }
 166 
 167         parent = kzalloc(sizeof(*parent), GFP_KERNEL);
 168         if (!parent) {
 169                 ret = -ENOMEM;
 170                 goto add_dev_err;
 171         }
 172 
 173         kref_init(&parent->ref);
 174         init_rwsem(&parent->unreg_sem);
 175 
 176         parent->dev = dev;
 177         parent->ops = ops;
 178 
 179         if (!mdev_bus_compat_class) {
 180                 mdev_bus_compat_class = class_compat_register("mdev_bus");
 181                 if (!mdev_bus_compat_class) {
 182                         ret = -ENOMEM;
 183                         goto add_dev_err;
 184                 }
 185         }
 186 
 187         ret = parent_create_sysfs_files(parent);
 188         if (ret)
 189                 goto add_dev_err;
 190 
 191         ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL);
 192         if (ret)
 193                 dev_warn(dev, "Failed to create compatibility class link\n");
 194 
 195         list_add(&parent->next, &parent_list);
 196         mutex_unlock(&parent_list_lock);
 197 
 198         dev_info(dev, "MDEV: Registered\n");
 199         kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 200 
 201         return 0;
 202 
 203 add_dev_err:
 204         mutex_unlock(&parent_list_lock);
 205         if (parent)
 206                 mdev_put_parent(parent);
 207         else
 208                 put_device(dev);
 209         return ret;
 210 }
 211 EXPORT_SYMBOL(mdev_register_device);
 212 
 213 /*
 214  * mdev_unregister_device : Unregister a parent device
 215  * @dev: device structure representing parent device.
 216  *
 217  * Remove device from list of registered parent devices. Give a chance to free
 218  * existing mediated devices for given device.
 219  */
 220 
 221 void mdev_unregister_device(struct device *dev)
 222 {
 223         struct mdev_parent *parent;
 224         char *env_string = "MDEV_STATE=unregistered";
 225         char *envp[] = { env_string, NULL };
 226 
 227         mutex_lock(&parent_list_lock);
 228         parent = __find_parent_device(dev);
 229 
 230         if (!parent) {
 231                 mutex_unlock(&parent_list_lock);
 232                 return;
 233         }
 234         dev_info(dev, "MDEV: Unregistering\n");
 235 
 236         list_del(&parent->next);
 237         mutex_unlock(&parent_list_lock);
 238 
 239         down_write(&parent->unreg_sem);
 240 
 241         class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
 242 
 243         device_for_each_child(dev, NULL, mdev_device_remove_cb);
 244 
 245         parent_remove_sysfs_files(parent);
 246         up_write(&parent->unreg_sem);
 247 
 248         mdev_put_parent(parent);
 249 
 250         /* We still have the caller's reference to use for the uevent */
 251         kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 252 }
 253 EXPORT_SYMBOL(mdev_unregister_device);
 254 
 255 static void mdev_device_free(struct mdev_device *mdev)
 256 {
 257         mutex_lock(&mdev_list_lock);
 258         list_del(&mdev->next);
 259         mutex_unlock(&mdev_list_lock);
 260 
 261         dev_dbg(&mdev->dev, "MDEV: destroying\n");
 262         kfree(mdev);
 263 }
 264 
 265 static void mdev_device_release(struct device *dev)
 266 {
 267         struct mdev_device *mdev = to_mdev_device(dev);
 268 
 269         mdev_device_free(mdev);
 270 }
 271 
 272 int mdev_device_create(struct kobject *kobj,
 273                        struct device *dev, const guid_t *uuid)
 274 {
 275         int ret;
 276         struct mdev_device *mdev, *tmp;
 277         struct mdev_parent *parent;
 278         struct mdev_type *type = to_mdev_type(kobj);
 279 
 280         parent = mdev_get_parent(type->parent);
 281         if (!parent)
 282                 return -EINVAL;
 283 
 284         mutex_lock(&mdev_list_lock);
 285 
 286         /* Check for duplicate */
 287         list_for_each_entry(tmp, &mdev_list, next) {
 288                 if (guid_equal(&tmp->uuid, uuid)) {
 289                         mutex_unlock(&mdev_list_lock);
 290                         ret = -EEXIST;
 291                         goto mdev_fail;
 292                 }
 293         }
 294 
 295         mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
 296         if (!mdev) {
 297                 mutex_unlock(&mdev_list_lock);
 298                 ret = -ENOMEM;
 299                 goto mdev_fail;
 300         }
 301 
 302         guid_copy(&mdev->uuid, uuid);
 303         list_add(&mdev->next, &mdev_list);
 304         mutex_unlock(&mdev_list_lock);
 305 
 306         mdev->parent = parent;
 307 
 308         /* Check if parent unregistration has started */
 309         if (!down_read_trylock(&parent->unreg_sem)) {
 310                 mdev_device_free(mdev);
 311                 ret = -ENODEV;
 312                 goto mdev_fail;
 313         }
 314 
 315         device_initialize(&mdev->dev);
 316         mdev->dev.parent  = dev;
 317         mdev->dev.bus     = &mdev_bus_type;
 318         mdev->dev.release = mdev_device_release;
 319         dev_set_name(&mdev->dev, "%pUl", uuid);
 320         mdev->dev.groups = parent->ops->mdev_attr_groups;
 321         mdev->type_kobj = kobj;
 322 
 323         ret = parent->ops->create(kobj, mdev);
 324         if (ret)
 325                 goto ops_create_fail;
 326 
 327         ret = device_add(&mdev->dev);
 328         if (ret)
 329                 goto add_fail;
 330 
 331         ret = mdev_create_sysfs_files(&mdev->dev, type);
 332         if (ret)
 333                 goto sysfs_fail;
 334 
 335         mdev->active = true;
 336         dev_dbg(&mdev->dev, "MDEV: created\n");
 337         up_read(&parent->unreg_sem);
 338 
 339         return 0;
 340 
 341 sysfs_fail:
 342         device_del(&mdev->dev);
 343 add_fail:
 344         parent->ops->remove(mdev);
 345 ops_create_fail:
 346         up_read(&parent->unreg_sem);
 347         put_device(&mdev->dev);
 348 mdev_fail:
 349         mdev_put_parent(parent);
 350         return ret;
 351 }
 352 
 353 int mdev_device_remove(struct device *dev)
 354 {
 355         struct mdev_device *mdev, *tmp;
 356         struct mdev_parent *parent;
 357 
 358         mdev = to_mdev_device(dev);
 359 
 360         mutex_lock(&mdev_list_lock);
 361         list_for_each_entry(tmp, &mdev_list, next) {
 362                 if (tmp == mdev)
 363                         break;
 364         }
 365 
 366         if (tmp != mdev) {
 367                 mutex_unlock(&mdev_list_lock);
 368                 return -ENODEV;
 369         }
 370 
 371         if (!mdev->active) {
 372                 mutex_unlock(&mdev_list_lock);
 373                 return -EAGAIN;
 374         }
 375 
 376         mdev->active = false;
 377         mutex_unlock(&mdev_list_lock);
 378 
 379         parent = mdev->parent;
 380         /* Check if parent unregistration has started */
 381         if (!down_read_trylock(&parent->unreg_sem))
 382                 return -ENODEV;
 383 
 384         mdev_device_remove_common(mdev);
 385         up_read(&parent->unreg_sem);
 386         return 0;
 387 }
 388 
 389 int mdev_set_iommu_device(struct device *dev, struct device *iommu_device)
 390 {
 391         struct mdev_device *mdev = to_mdev_device(dev);
 392 
 393         mdev->iommu_device = iommu_device;
 394 
 395         return 0;
 396 }
 397 EXPORT_SYMBOL(mdev_set_iommu_device);
 398 
 399 struct device *mdev_get_iommu_device(struct device *dev)
 400 {
 401         struct mdev_device *mdev = to_mdev_device(dev);
 402 
 403         return mdev->iommu_device;
 404 }
 405 EXPORT_SYMBOL(mdev_get_iommu_device);
 406 
 407 static int __init mdev_init(void)
 408 {
 409         return mdev_bus_register();
 410 }
 411 
 412 static void __exit mdev_exit(void)
 413 {
 414         if (mdev_bus_compat_class)
 415                 class_compat_unregister(mdev_bus_compat_class);
 416 
 417         mdev_bus_unregister();
 418 }
 419 
 420 module_init(mdev_init)
 421 module_exit(mdev_exit)
 422 
 423 MODULE_VERSION(DRIVER_VERSION);
 424 MODULE_LICENSE("GPL v2");
 425 MODULE_AUTHOR(DRIVER_AUTHOR);
 426 MODULE_DESCRIPTION(DRIVER_DESC);
 427 MODULE_SOFTDEP("post: vfio_mdev");

/* [<][>][^][v][top][bottom][index][help] */