0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/device.h>
0012 #include <linux/slab.h>
0013 #include <linux/uuid.h>
0014 #include <linux/sysfs.h>
0015 #include <linux/mdev.h>
0016
0017 #include "mdev_private.h"
0018
0019 #define DRIVER_VERSION "0.1"
0020 #define DRIVER_AUTHOR "NVIDIA Corporation"
0021 #define DRIVER_DESC "Mediated device Core Driver"
0022
0023 static LIST_HEAD(parent_list);
0024 static DEFINE_MUTEX(parent_list_lock);
0025 static struct class_compat *mdev_bus_compat_class;
0026
0027 static LIST_HEAD(mdev_list);
0028 static DEFINE_MUTEX(mdev_list_lock);
0029
0030 struct device *mdev_parent_dev(struct mdev_device *mdev)
0031 {
0032 return mdev->type->parent->dev;
0033 }
0034 EXPORT_SYMBOL(mdev_parent_dev);
0035
0036
0037
0038
0039
0040 unsigned int mdev_get_type_group_id(struct mdev_device *mdev)
0041 {
0042 return mdev->type->type_group_id;
0043 }
0044 EXPORT_SYMBOL(mdev_get_type_group_id);
0045
0046
0047
0048
0049
0050 unsigned int mtype_get_type_group_id(struct mdev_type *mtype)
0051 {
0052 return mtype->type_group_id;
0053 }
0054 EXPORT_SYMBOL(mtype_get_type_group_id);
0055
0056
0057
0058
0059
0060 struct device *mtype_get_parent_dev(struct mdev_type *mtype)
0061 {
0062 return mtype->parent->dev;
0063 }
0064 EXPORT_SYMBOL(mtype_get_parent_dev);
0065
0066
0067 static struct mdev_parent *__find_parent_device(struct device *dev)
0068 {
0069 struct mdev_parent *parent;
0070
0071 list_for_each_entry(parent, &parent_list, next) {
0072 if (parent->dev == dev)
0073 return parent;
0074 }
0075 return NULL;
0076 }
0077
0078 void mdev_release_parent(struct kref *kref)
0079 {
0080 struct mdev_parent *parent = container_of(kref, struct mdev_parent,
0081 ref);
0082 struct device *dev = parent->dev;
0083
0084 kfree(parent);
0085 put_device(dev);
0086 }
0087
0088
0089 static void mdev_device_remove_common(struct mdev_device *mdev)
0090 {
0091 struct mdev_parent *parent = mdev->type->parent;
0092
0093 mdev_remove_sysfs_files(mdev);
0094 device_del(&mdev->dev);
0095 lockdep_assert_held(&parent->unreg_sem);
0096
0097 put_device(&mdev->dev);
0098 }
0099
0100 static int mdev_device_remove_cb(struct device *dev, void *data)
0101 {
0102 struct mdev_device *mdev = mdev_from_dev(dev);
0103
0104 if (mdev)
0105 mdev_device_remove_common(mdev);
0106 return 0;
0107 }
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117 int mdev_register_device(struct device *dev, struct mdev_driver *mdev_driver)
0118 {
0119 int ret;
0120 struct mdev_parent *parent;
0121 char *env_string = "MDEV_STATE=registered";
0122 char *envp[] = { env_string, NULL };
0123
0124
0125 if (!mdev_driver->supported_type_groups)
0126 return -EINVAL;
0127
0128 dev = get_device(dev);
0129 if (!dev)
0130 return -EINVAL;
0131
0132 mutex_lock(&parent_list_lock);
0133
0134
0135 parent = __find_parent_device(dev);
0136 if (parent) {
0137 parent = NULL;
0138 ret = -EEXIST;
0139 goto add_dev_err;
0140 }
0141
0142 parent = kzalloc(sizeof(*parent), GFP_KERNEL);
0143 if (!parent) {
0144 ret = -ENOMEM;
0145 goto add_dev_err;
0146 }
0147
0148 kref_init(&parent->ref);
0149 init_rwsem(&parent->unreg_sem);
0150
0151 parent->dev = dev;
0152 parent->mdev_driver = mdev_driver;
0153
0154 if (!mdev_bus_compat_class) {
0155 mdev_bus_compat_class = class_compat_register("mdev_bus");
0156 if (!mdev_bus_compat_class) {
0157 ret = -ENOMEM;
0158 goto add_dev_err;
0159 }
0160 }
0161
0162 ret = parent_create_sysfs_files(parent);
0163 if (ret)
0164 goto add_dev_err;
0165
0166 ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL);
0167 if (ret)
0168 dev_warn(dev, "Failed to create compatibility class link\n");
0169
0170 list_add(&parent->next, &parent_list);
0171 mutex_unlock(&parent_list_lock);
0172
0173 dev_info(dev, "MDEV: Registered\n");
0174 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
0175
0176 return 0;
0177
0178 add_dev_err:
0179 mutex_unlock(&parent_list_lock);
0180 if (parent)
0181 mdev_put_parent(parent);
0182 else
0183 put_device(dev);
0184 return ret;
0185 }
0186 EXPORT_SYMBOL(mdev_register_device);
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196 void mdev_unregister_device(struct device *dev)
0197 {
0198 struct mdev_parent *parent;
0199 char *env_string = "MDEV_STATE=unregistered";
0200 char *envp[] = { env_string, NULL };
0201
0202 mutex_lock(&parent_list_lock);
0203 parent = __find_parent_device(dev);
0204
0205 if (!parent) {
0206 mutex_unlock(&parent_list_lock);
0207 return;
0208 }
0209 dev_info(dev, "MDEV: Unregistering\n");
0210
0211 list_del(&parent->next);
0212 mutex_unlock(&parent_list_lock);
0213
0214 down_write(&parent->unreg_sem);
0215
0216 class_compat_remove_link(mdev_bus_compat_class, dev, NULL);
0217
0218 device_for_each_child(dev, NULL, mdev_device_remove_cb);
0219
0220 parent_remove_sysfs_files(parent);
0221 up_write(&parent->unreg_sem);
0222
0223 mdev_put_parent(parent);
0224
0225
0226 kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
0227 }
0228 EXPORT_SYMBOL(mdev_unregister_device);
0229
0230 static void mdev_device_release(struct device *dev)
0231 {
0232 struct mdev_device *mdev = to_mdev_device(dev);
0233
0234
0235 kobject_put(&mdev->type->kobj);
0236
0237 mutex_lock(&mdev_list_lock);
0238 list_del(&mdev->next);
0239 mutex_unlock(&mdev_list_lock);
0240
0241 dev_dbg(&mdev->dev, "MDEV: destroying\n");
0242 kfree(mdev);
0243 }
0244
0245 int mdev_device_create(struct mdev_type *type, const guid_t *uuid)
0246 {
0247 int ret;
0248 struct mdev_device *mdev, *tmp;
0249 struct mdev_parent *parent = type->parent;
0250 struct mdev_driver *drv = parent->mdev_driver;
0251
0252 mutex_lock(&mdev_list_lock);
0253
0254
0255 list_for_each_entry(tmp, &mdev_list, next) {
0256 if (guid_equal(&tmp->uuid, uuid)) {
0257 mutex_unlock(&mdev_list_lock);
0258 return -EEXIST;
0259 }
0260 }
0261
0262 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
0263 if (!mdev) {
0264 mutex_unlock(&mdev_list_lock);
0265 return -ENOMEM;
0266 }
0267
0268 device_initialize(&mdev->dev);
0269 mdev->dev.parent = parent->dev;
0270 mdev->dev.bus = &mdev_bus_type;
0271 mdev->dev.release = mdev_device_release;
0272 mdev->dev.groups = mdev_device_groups;
0273 mdev->type = type;
0274
0275 kobject_get(&type->kobj);
0276
0277 guid_copy(&mdev->uuid, uuid);
0278 list_add(&mdev->next, &mdev_list);
0279 mutex_unlock(&mdev_list_lock);
0280
0281 ret = dev_set_name(&mdev->dev, "%pUl", uuid);
0282 if (ret)
0283 goto out_put_device;
0284
0285
0286 if (!down_read_trylock(&parent->unreg_sem)) {
0287 ret = -ENODEV;
0288 goto out_put_device;
0289 }
0290
0291 ret = device_add(&mdev->dev);
0292 if (ret)
0293 goto out_unlock;
0294
0295 ret = device_driver_attach(&drv->driver, &mdev->dev);
0296 if (ret)
0297 goto out_del;
0298
0299 ret = mdev_create_sysfs_files(mdev);
0300 if (ret)
0301 goto out_del;
0302
0303 mdev->active = true;
0304 dev_dbg(&mdev->dev, "MDEV: created\n");
0305 up_read(&parent->unreg_sem);
0306
0307 return 0;
0308
0309 out_del:
0310 device_del(&mdev->dev);
0311 out_unlock:
0312 up_read(&parent->unreg_sem);
0313 out_put_device:
0314 put_device(&mdev->dev);
0315 return ret;
0316 }
0317
0318 int mdev_device_remove(struct mdev_device *mdev)
0319 {
0320 struct mdev_device *tmp;
0321 struct mdev_parent *parent = mdev->type->parent;
0322
0323 mutex_lock(&mdev_list_lock);
0324 list_for_each_entry(tmp, &mdev_list, next) {
0325 if (tmp == mdev)
0326 break;
0327 }
0328
0329 if (tmp != mdev) {
0330 mutex_unlock(&mdev_list_lock);
0331 return -ENODEV;
0332 }
0333
0334 if (!mdev->active) {
0335 mutex_unlock(&mdev_list_lock);
0336 return -EAGAIN;
0337 }
0338
0339 mdev->active = false;
0340 mutex_unlock(&mdev_list_lock);
0341
0342
0343 if (!down_read_trylock(&parent->unreg_sem))
0344 return -ENODEV;
0345
0346 mdev_device_remove_common(mdev);
0347 up_read(&parent->unreg_sem);
0348 return 0;
0349 }
0350
0351 static int __init mdev_init(void)
0352 {
0353 return bus_register(&mdev_bus_type);
0354 }
0355
0356 static void __exit mdev_exit(void)
0357 {
0358 if (mdev_bus_compat_class)
0359 class_compat_unregister(mdev_bus_compat_class);
0360 bus_unregister(&mdev_bus_type);
0361 }
0362
0363 subsys_initcall(mdev_init)
0364 module_exit(mdev_exit)
0365
0366 MODULE_VERSION(DRIVER_VERSION);
0367 MODULE_LICENSE("GPL v2");
0368 MODULE_AUTHOR(DRIVER_AUTHOR);
0369 MODULE_DESCRIPTION(DRIVER_DESC);