1925f5afeSJiri Pirko // SPDX-License-Identifier: GPL-2.0 2925f5afeSJiri Pirko /* Copyright (C) 2017 Netronome Systems, Inc. 3925f5afeSJiri Pirko * Copyright (C) 2019 Mellanox Technologies. All rights reserved 4925f5afeSJiri Pirko */ 5925f5afeSJiri Pirko 6925f5afeSJiri Pirko #include <linux/device.h> 757ce9774SJiri Pirko #include <linux/idr.h> 840e4fe4cSJiri Pirko #include <linux/kernel.h> 9f9d9db47SJiri Pirko #include <linux/list.h> 10f9d9db47SJiri Pirko #include <linux/mutex.h> 1140e4fe4cSJiri Pirko #include <linux/slab.h> 1240e4fe4cSJiri Pirko #include <linux/sysfs.h> 13925f5afeSJiri Pirko 14925f5afeSJiri Pirko #include "netdevsim.h" 15925f5afeSJiri Pirko 1657ce9774SJiri Pirko static DEFINE_IDA(nsim_bus_dev_ids); 17f9d9db47SJiri Pirko static LIST_HEAD(nsim_bus_dev_list); 18f9d9db47SJiri Pirko static DEFINE_MUTEX(nsim_bus_dev_list_lock); 19f5cd2160STaehee Yoo static bool nsim_bus_enable; 2040e4fe4cSJiri Pirko 2140e4fe4cSJiri Pirko static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev) 2240e4fe4cSJiri Pirko { 2340e4fe4cSJiri Pirko return container_of(dev, struct nsim_bus_dev, dev); 2440e4fe4cSJiri Pirko } 2540e4fe4cSJiri Pirko 2640e4fe4cSJiri Pirko static ssize_t 2740e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 2840e4fe4cSJiri Pirko const char *buf, size_t count) 2940e4fe4cSJiri Pirko { 3040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3140e4fe4cSJiri Pirko unsigned int num_vfs; 3240e4fe4cSJiri Pirko int ret; 3340e4fe4cSJiri Pirko 3440e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 3540e4fe4cSJiri Pirko if (ret) 3640e4fe4cSJiri Pirko return ret; 3740e4fe4cSJiri Pirko 385e388f3dSJakub Kicinski device_lock(dev); 395e388f3dSJakub Kicinski ret = -ENOENT; 401c401078SJakub Kicinski if (dev_get_drvdata(dev)) 411c401078SJakub Kicinski ret = nsim_drv_configure_vfs(nsim_bus_dev, num_vfs); 425e388f3dSJakub Kicinski device_unlock(dev); 4340e4fe4cSJiri Pirko 441c401078SJakub Kicinski return ret ? ret : count; 4540e4fe4cSJiri Pirko } 4640e4fe4cSJiri Pirko 4740e4fe4cSJiri Pirko static ssize_t 4840e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 4940e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 5040e4fe4cSJiri Pirko { 5140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 5240e4fe4cSJiri Pirko 5340e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 5440e4fe4cSJiri Pirko } 5540e4fe4cSJiri Pirko 5640e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 5740e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 5840e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 5940e4fe4cSJiri Pirko 60794b2c05SJiri Pirko static ssize_t 61794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 62794b2c05SJiri Pirko const char *buf, size_t count) 63794b2c05SJiri Pirko { 64794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 65794b2c05SJiri Pirko unsigned int port_index; 66794b2c05SJiri Pirko int ret; 67794b2c05SJiri Pirko 68f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 69f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 70f5cd2160STaehee Yoo return -EBUSY; 71794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 72794b2c05SJiri Pirko if (ret) 73794b2c05SJiri Pirko return ret; 746ab63366STaehee Yoo 7523809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 7623809a72SLeon Romanovsky return -EBUSY; 776ab63366STaehee Yoo 785c0418edSLeon Romanovsky if (nsim_bus_dev->in_reload) { 795c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 805c0418edSLeon Romanovsky return -EBUSY; 815c0418edSLeon Romanovsky } 825c0418edSLeon Romanovsky 83*a66f64b8SJakub Kicinski ret = nsim_drv_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 846ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 85794b2c05SJiri Pirko return ret ? ret : count; 86794b2c05SJiri Pirko } 87794b2c05SJiri Pirko 88794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 89794b2c05SJiri Pirko 90794b2c05SJiri Pirko static ssize_t 91794b2c05SJiri Pirko del_port_store(struct device *dev, struct device_attribute *attr, 92794b2c05SJiri Pirko const char *buf, size_t count) 93794b2c05SJiri Pirko { 94794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 95794b2c05SJiri Pirko unsigned int port_index; 96794b2c05SJiri Pirko int ret; 97794b2c05SJiri Pirko 98f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 99f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 100f5cd2160STaehee Yoo return -EBUSY; 101794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 102794b2c05SJiri Pirko if (ret) 103794b2c05SJiri Pirko return ret; 1046ab63366STaehee Yoo 10523809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 10623809a72SLeon Romanovsky return -EBUSY; 1076ab63366STaehee Yoo 1085c0418edSLeon Romanovsky if (nsim_bus_dev->in_reload) { 1095c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 1105c0418edSLeon Romanovsky return -EBUSY; 1115c0418edSLeon Romanovsky } 1125c0418edSLeon Romanovsky 113*a66f64b8SJakub Kicinski ret = nsim_drv_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 1146ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 115794b2c05SJiri Pirko return ret ? ret : count; 116794b2c05SJiri Pirko } 117794b2c05SJiri Pirko 118794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 119794b2c05SJiri Pirko 12040e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 12140e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 122794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 123794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 12440e4fe4cSJiri Pirko NULL, 12540e4fe4cSJiri Pirko }; 12640e4fe4cSJiri Pirko 12740e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 12840e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 12940e4fe4cSJiri Pirko }; 13040e4fe4cSJiri Pirko 13140e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 13240e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 13340e4fe4cSJiri Pirko NULL, 13440e4fe4cSJiri Pirko }; 13540e4fe4cSJiri Pirko 13640e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 13740e4fe4cSJiri Pirko { 13840e4fe4cSJiri Pirko } 13940e4fe4cSJiri Pirko 14040e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 14140e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 14240e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 14340e4fe4cSJiri Pirko }; 14440e4fe4cSJiri Pirko 145e05b2d14SJiri Pirko static struct nsim_bus_dev * 146d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues); 147e05b2d14SJiri Pirko 148f9d9db47SJiri Pirko static ssize_t 149f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 150f9d9db47SJiri Pirko { 151d4861fc6SPeilin Ye unsigned int id, port_count, num_queues; 152f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 153f9d9db47SJiri Pirko int err; 154f9d9db47SJiri Pirko 155d4861fc6SPeilin Ye err = sscanf(buf, "%u %u %u", &id, &port_count, &num_queues); 156f9d9db47SJiri Pirko switch (err) { 157f9d9db47SJiri Pirko case 1: 158f9d9db47SJiri Pirko port_count = 1; 159df561f66SGustavo A. R. Silva fallthrough; 160f9d9db47SJiri Pirko case 2: 161d4861fc6SPeilin Ye num_queues = 1; 162d4861fc6SPeilin Ye fallthrough; 163d4861fc6SPeilin Ye case 3: 164f9d9db47SJiri Pirko if (id > INT_MAX) { 165f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 166f9d9db47SJiri Pirko return -EINVAL; 167f9d9db47SJiri Pirko } 168f9d9db47SJiri Pirko break; 169f9d9db47SJiri Pirko default: 170d4861fc6SPeilin Ye pr_err("Format for adding new device is \"id port_count num_queues\" (uint uint unit).\n"); 171f9d9db47SJiri Pirko return -EINVAL; 172f9d9db47SJiri Pirko } 173f9d9db47SJiri Pirko 174f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 175f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 176f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 177f5cd2160STaehee Yoo err = -EBUSY; 178f5cd2160STaehee Yoo goto err; 179f5cd2160STaehee Yoo } 180f5cd2160STaehee Yoo 181d4861fc6SPeilin Ye nsim_bus_dev = nsim_bus_dev_new(id, port_count, num_queues); 182f5cd2160STaehee Yoo if (IS_ERR(nsim_bus_dev)) { 183f5cd2160STaehee Yoo err = PTR_ERR(nsim_bus_dev); 184f5cd2160STaehee Yoo goto err; 185f5cd2160STaehee Yoo } 186f5cd2160STaehee Yoo 187f5cd2160STaehee Yoo /* Allow using nsim_bus_dev */ 188f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, true); 189f5cd2160STaehee Yoo 190f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 191f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 192f9d9db47SJiri Pirko 193f9d9db47SJiri Pirko return count; 194f5cd2160STaehee Yoo err: 195f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 196f5cd2160STaehee Yoo return err; 197f9d9db47SJiri Pirko } 198f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 199f9d9db47SJiri Pirko 200e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 201e05b2d14SJiri Pirko 202f9d9db47SJiri Pirko static ssize_t 203f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 204f9d9db47SJiri Pirko { 205f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 206f9d9db47SJiri Pirko unsigned int id; 207f9d9db47SJiri Pirko int err; 208f9d9db47SJiri Pirko 209f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 210f9d9db47SJiri Pirko switch (err) { 211f9d9db47SJiri Pirko case 1: 212f9d9db47SJiri Pirko if (id > INT_MAX) { 213f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 214f9d9db47SJiri Pirko return -EINVAL; 215f9d9db47SJiri Pirko } 216f9d9db47SJiri Pirko break; 217f9d9db47SJiri Pirko default: 218f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 219f9d9db47SJiri Pirko return -EINVAL; 220f9d9db47SJiri Pirko } 221f9d9db47SJiri Pirko 222f9d9db47SJiri Pirko err = -ENOENT; 223f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 224f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 225f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 226f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 227f5cd2160STaehee Yoo return -EBUSY; 228f5cd2160STaehee Yoo } 229f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 230f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 231f9d9db47SJiri Pirko continue; 232f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 233f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 234f9d9db47SJiri Pirko err = 0; 235f9d9db47SJiri Pirko break; 236f9d9db47SJiri Pirko } 237f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 238f9d9db47SJiri Pirko return !err ? count : err; 239f9d9db47SJiri Pirko } 240f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 241f9d9db47SJiri Pirko 242f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 243f9d9db47SJiri Pirko &bus_attr_new_device.attr, 244f9d9db47SJiri Pirko &bus_attr_del_device.attr, 245f9d9db47SJiri Pirko NULL 246f9d9db47SJiri Pirko }; 247f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 248f9d9db47SJiri Pirko 2498320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 2508320d145SJiri Pirko { 2518320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2528320d145SJiri Pirko 253*a66f64b8SJakub Kicinski return nsim_drv_probe(nsim_bus_dev); 2548320d145SJiri Pirko } 2558320d145SJiri Pirko 256fc7a6209SUwe Kleine-König static void nsim_bus_remove(struct device *dev) 2578320d145SJiri Pirko { 2588320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2598320d145SJiri Pirko 260*a66f64b8SJakub Kicinski nsim_drv_remove(nsim_bus_dev); 2618320d145SJiri Pirko } 2628320d145SJiri Pirko 26369bbbdc5SYueHaibing static int nsim_num_vf(struct device *dev) 26440e4fe4cSJiri Pirko { 26540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 26640e4fe4cSJiri Pirko 26740e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 26840e4fe4cSJiri Pirko } 26940e4fe4cSJiri Pirko 27040e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 271925f5afeSJiri Pirko .name = DRV_NAME, 272925f5afeSJiri Pirko .dev_name = DRV_NAME, 273f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 2748320d145SJiri Pirko .probe = nsim_bus_probe, 2758320d145SJiri Pirko .remove = nsim_bus_remove, 276925f5afeSJiri Pirko .num_vf = nsim_num_vf, 277925f5afeSJiri Pirko }; 278925f5afeSJiri Pirko 279d3953819SDmytro Linkin #define NSIM_BUS_DEV_MAX_VFS 4 280d3953819SDmytro Linkin 281e05b2d14SJiri Pirko static struct nsim_bus_dev * 282d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues) 28340e4fe4cSJiri Pirko { 28440e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 28540e4fe4cSJiri Pirko int err; 28640e4fe4cSJiri Pirko 28740e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 28840e4fe4cSJiri Pirko if (!nsim_bus_dev) 28940e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 29040e4fe4cSJiri Pirko 291e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 29257ce9774SJiri Pirko if (err < 0) 29357ce9774SJiri Pirko goto err_nsim_bus_dev_free; 29457ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 29540e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 29640e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 297f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 298d4861fc6SPeilin Ye nsim_bus_dev->num_queues = num_queues; 2997b60027bSJiri Pirko nsim_bus_dev->initial_net = current->nsproxy->net_ns; 300d3953819SDmytro Linkin nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS; 3016ab63366STaehee Yoo mutex_init(&nsim_bus_dev->nsim_bus_reload_lock); 302f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 303f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 304f9d9db47SJiri Pirko 30540e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 30640e4fe4cSJiri Pirko if (err) 3075e388f3dSJakub Kicinski goto err_nsim_bus_dev_id_free; 308d3953819SDmytro Linkin 30940e4fe4cSJiri Pirko return nsim_bus_dev; 31040e4fe4cSJiri Pirko 31157ce9774SJiri Pirko err_nsim_bus_dev_id_free: 31257ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 31340e4fe4cSJiri Pirko err_nsim_bus_dev_free: 31440e4fe4cSJiri Pirko kfree(nsim_bus_dev); 31540e4fe4cSJiri Pirko return ERR_PTR(err); 31640e4fe4cSJiri Pirko } 31740e4fe4cSJiri Pirko 318e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 31940e4fe4cSJiri Pirko { 320f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 321f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 32240e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 32357ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 32440e4fe4cSJiri Pirko kfree(nsim_bus_dev); 32540e4fe4cSJiri Pirko } 32640e4fe4cSJiri Pirko 32723d415daSJiri Pirko static struct device_driver nsim_driver = { 32823d415daSJiri Pirko .name = DRV_NAME, 32923d415daSJiri Pirko .bus = &nsim_bus, 33023d415daSJiri Pirko .owner = THIS_MODULE, 33123d415daSJiri Pirko }; 33223d415daSJiri Pirko 333925f5afeSJiri Pirko int nsim_bus_init(void) 334925f5afeSJiri Pirko { 33523d415daSJiri Pirko int err; 33623d415daSJiri Pirko 33723d415daSJiri Pirko err = bus_register(&nsim_bus); 33823d415daSJiri Pirko if (err) 33923d415daSJiri Pirko return err; 34023d415daSJiri Pirko err = driver_register(&nsim_driver); 34123d415daSJiri Pirko if (err) 34223d415daSJiri Pirko goto err_bus_unregister; 343f5cd2160STaehee Yoo /* Allow using resources */ 344f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, true); 34523d415daSJiri Pirko return 0; 34623d415daSJiri Pirko 34723d415daSJiri Pirko err_bus_unregister: 34823d415daSJiri Pirko bus_unregister(&nsim_bus); 34923d415daSJiri Pirko return err; 350925f5afeSJiri Pirko } 351925f5afeSJiri Pirko 352925f5afeSJiri Pirko void nsim_bus_exit(void) 353925f5afeSJiri Pirko { 354f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 355f9d9db47SJiri Pirko 356f5cd2160STaehee Yoo /* Disallow using resources */ 357f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, false); 358f5cd2160STaehee Yoo 359f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 360f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 361f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 362f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 363f9d9db47SJiri Pirko } 364f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 365f5cd2160STaehee Yoo 36623d415daSJiri Pirko driver_unregister(&nsim_driver); 367925f5afeSJiri Pirko bus_unregister(&nsim_bus); 368925f5afeSJiri Pirko } 369