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/rtnetlink.h> 1240e4fe4cSJiri Pirko #include <linux/slab.h> 1340e4fe4cSJiri Pirko #include <linux/sysfs.h> 14925f5afeSJiri Pirko 15925f5afeSJiri Pirko #include "netdevsim.h" 16925f5afeSJiri Pirko 1757ce9774SJiri Pirko static DEFINE_IDA(nsim_bus_dev_ids); 18f9d9db47SJiri Pirko static LIST_HEAD(nsim_bus_dev_list); 19f9d9db47SJiri Pirko static DEFINE_MUTEX(nsim_bus_dev_list_lock); 20f5cd2160STaehee Yoo static bool nsim_bus_enable; 2140e4fe4cSJiri Pirko 2240e4fe4cSJiri Pirko static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev) 2340e4fe4cSJiri Pirko { 2440e4fe4cSJiri Pirko return container_of(dev, struct nsim_bus_dev, dev); 2540e4fe4cSJiri Pirko } 2640e4fe4cSJiri Pirko 2740e4fe4cSJiri Pirko static int nsim_bus_dev_vfs_enable(struct nsim_bus_dev *nsim_bus_dev, 2840e4fe4cSJiri Pirko unsigned int num_vfs) 2940e4fe4cSJiri Pirko { 3040e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs = kcalloc(num_vfs, 3140e4fe4cSJiri Pirko sizeof(struct nsim_vf_config), 3240e4fe4cSJiri Pirko GFP_KERNEL); 3340e4fe4cSJiri Pirko if (!nsim_bus_dev->vfconfigs) 3440e4fe4cSJiri Pirko return -ENOMEM; 3540e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = num_vfs; 3640e4fe4cSJiri Pirko 3740e4fe4cSJiri Pirko return 0; 3840e4fe4cSJiri Pirko } 3940e4fe4cSJiri Pirko 4040e4fe4cSJiri Pirko static void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev) 4140e4fe4cSJiri Pirko { 4240e4fe4cSJiri Pirko kfree(nsim_bus_dev->vfconfigs); 4340e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs = NULL; 4440e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = 0; 4540e4fe4cSJiri Pirko } 4640e4fe4cSJiri Pirko 4740e4fe4cSJiri Pirko static ssize_t 4840e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 4940e4fe4cSJiri Pirko const char *buf, size_t count) 5040e4fe4cSJiri Pirko { 5140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 5240e4fe4cSJiri Pirko unsigned int num_vfs; 5340e4fe4cSJiri Pirko int ret; 5440e4fe4cSJiri Pirko 5540e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 5640e4fe4cSJiri Pirko if (ret) 5740e4fe4cSJiri Pirko return ret; 5840e4fe4cSJiri Pirko 5940e4fe4cSJiri Pirko rtnl_lock(); 6040e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs == num_vfs) 6140e4fe4cSJiri Pirko goto exit_good; 6240e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs && num_vfs) { 6340e4fe4cSJiri Pirko ret = -EBUSY; 6440e4fe4cSJiri Pirko goto exit_unlock; 6540e4fe4cSJiri Pirko } 6640e4fe4cSJiri Pirko 6740e4fe4cSJiri Pirko if (num_vfs) { 6840e4fe4cSJiri Pirko ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs); 6940e4fe4cSJiri Pirko if (ret) 7040e4fe4cSJiri Pirko goto exit_unlock; 7140e4fe4cSJiri Pirko } else { 7240e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 7340e4fe4cSJiri Pirko } 7440e4fe4cSJiri Pirko exit_good: 7540e4fe4cSJiri Pirko ret = count; 7640e4fe4cSJiri Pirko exit_unlock: 7740e4fe4cSJiri Pirko rtnl_unlock(); 7840e4fe4cSJiri Pirko 7940e4fe4cSJiri Pirko return ret; 8040e4fe4cSJiri Pirko } 8140e4fe4cSJiri Pirko 8240e4fe4cSJiri Pirko static ssize_t 8340e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 8440e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 8540e4fe4cSJiri Pirko { 8640e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 8740e4fe4cSJiri Pirko 8840e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 8940e4fe4cSJiri Pirko } 9040e4fe4cSJiri Pirko 9140e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 9240e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 9340e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 9440e4fe4cSJiri Pirko 95794b2c05SJiri Pirko static ssize_t 96794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 97794b2c05SJiri Pirko const char *buf, size_t count) 98794b2c05SJiri Pirko { 99794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 100*6ab63366STaehee Yoo struct nsim_dev *nsim_dev = dev_get_drvdata(dev); 101*6ab63366STaehee Yoo struct devlink *devlink; 102794b2c05SJiri Pirko unsigned int port_index; 103794b2c05SJiri Pirko int ret; 104794b2c05SJiri Pirko 105f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 106f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 107f5cd2160STaehee Yoo return -EBUSY; 108794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 109794b2c05SJiri Pirko if (ret) 110794b2c05SJiri Pirko return ret; 111*6ab63366STaehee Yoo 112*6ab63366STaehee Yoo devlink = priv_to_devlink(nsim_dev); 113*6ab63366STaehee Yoo 114*6ab63366STaehee Yoo mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 115*6ab63366STaehee Yoo devlink_reload_disable(devlink); 116794b2c05SJiri Pirko ret = nsim_dev_port_add(nsim_bus_dev, port_index); 117*6ab63366STaehee Yoo devlink_reload_enable(devlink); 118*6ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 119794b2c05SJiri Pirko return ret ? ret : count; 120794b2c05SJiri Pirko } 121794b2c05SJiri Pirko 122794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 123794b2c05SJiri Pirko 124794b2c05SJiri Pirko static ssize_t 125794b2c05SJiri Pirko del_port_store(struct device *dev, struct device_attribute *attr, 126794b2c05SJiri Pirko const char *buf, size_t count) 127794b2c05SJiri Pirko { 128794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 129*6ab63366STaehee Yoo struct nsim_dev *nsim_dev = dev_get_drvdata(dev); 130*6ab63366STaehee Yoo struct devlink *devlink; 131794b2c05SJiri Pirko unsigned int port_index; 132794b2c05SJiri Pirko int ret; 133794b2c05SJiri Pirko 134f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 135f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 136f5cd2160STaehee Yoo return -EBUSY; 137794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 138794b2c05SJiri Pirko if (ret) 139794b2c05SJiri Pirko return ret; 140*6ab63366STaehee Yoo 141*6ab63366STaehee Yoo devlink = priv_to_devlink(nsim_dev); 142*6ab63366STaehee Yoo 143*6ab63366STaehee Yoo mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 144*6ab63366STaehee Yoo devlink_reload_disable(devlink); 145794b2c05SJiri Pirko ret = nsim_dev_port_del(nsim_bus_dev, port_index); 146*6ab63366STaehee Yoo devlink_reload_enable(devlink); 147*6ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 148794b2c05SJiri Pirko return ret ? ret : count; 149794b2c05SJiri Pirko } 150794b2c05SJiri Pirko 151794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 152794b2c05SJiri Pirko 15340e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 15440e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 155794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 156794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 15740e4fe4cSJiri Pirko NULL, 15840e4fe4cSJiri Pirko }; 15940e4fe4cSJiri Pirko 16040e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 16140e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 16240e4fe4cSJiri Pirko }; 16340e4fe4cSJiri Pirko 16440e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 16540e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 16640e4fe4cSJiri Pirko NULL, 16740e4fe4cSJiri Pirko }; 16840e4fe4cSJiri Pirko 16940e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 17040e4fe4cSJiri Pirko { 17140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 17240e4fe4cSJiri Pirko 17340e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 17440e4fe4cSJiri Pirko } 17540e4fe4cSJiri Pirko 17640e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 17740e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 17840e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 17940e4fe4cSJiri Pirko }; 18040e4fe4cSJiri Pirko 181e05b2d14SJiri Pirko static struct nsim_bus_dev * 182e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count); 183e05b2d14SJiri Pirko 184f9d9db47SJiri Pirko static ssize_t 185f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 186f9d9db47SJiri Pirko { 187f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 188f9d9db47SJiri Pirko unsigned int port_count; 189f9d9db47SJiri Pirko unsigned int id; 190f9d9db47SJiri Pirko int err; 191f9d9db47SJiri Pirko 192f9d9db47SJiri Pirko err = sscanf(buf, "%u %u", &id, &port_count); 193f9d9db47SJiri Pirko switch (err) { 194f9d9db47SJiri Pirko case 1: 195f9d9db47SJiri Pirko port_count = 1; 1966d1474a9SGustavo A. R. Silva /* fall through */ 197f9d9db47SJiri Pirko case 2: 198f9d9db47SJiri Pirko if (id > INT_MAX) { 199f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 200f9d9db47SJiri Pirko return -EINVAL; 201f9d9db47SJiri Pirko } 202f9d9db47SJiri Pirko break; 203f9d9db47SJiri Pirko default: 204f9d9db47SJiri Pirko pr_err("Format for adding new device is \"id port_count\" (uint uint).\n"); 205f9d9db47SJiri Pirko return -EINVAL; 206f9d9db47SJiri Pirko } 207f9d9db47SJiri Pirko 208f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 209f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 210f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 211f5cd2160STaehee Yoo err = -EBUSY; 212f5cd2160STaehee Yoo goto err; 213f5cd2160STaehee Yoo } 214f5cd2160STaehee Yoo 215f5cd2160STaehee Yoo nsim_bus_dev = nsim_bus_dev_new(id, port_count); 216f5cd2160STaehee Yoo if (IS_ERR(nsim_bus_dev)) { 217f5cd2160STaehee Yoo err = PTR_ERR(nsim_bus_dev); 218f5cd2160STaehee Yoo goto err; 219f5cd2160STaehee Yoo } 220f5cd2160STaehee Yoo 221f5cd2160STaehee Yoo /* Allow using nsim_bus_dev */ 222f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, true); 223f5cd2160STaehee Yoo 224f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 225f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 226f9d9db47SJiri Pirko 227f9d9db47SJiri Pirko return count; 228f5cd2160STaehee Yoo err: 229f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 230f5cd2160STaehee Yoo return err; 231f9d9db47SJiri Pirko } 232f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 233f9d9db47SJiri Pirko 234e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 235e05b2d14SJiri Pirko 236f9d9db47SJiri Pirko static ssize_t 237f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 238f9d9db47SJiri Pirko { 239f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 240f9d9db47SJiri Pirko unsigned int id; 241f9d9db47SJiri Pirko int err; 242f9d9db47SJiri Pirko 243f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 244f9d9db47SJiri Pirko switch (err) { 245f9d9db47SJiri Pirko case 1: 246f9d9db47SJiri Pirko if (id > INT_MAX) { 247f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 248f9d9db47SJiri Pirko return -EINVAL; 249f9d9db47SJiri Pirko } 250f9d9db47SJiri Pirko break; 251f9d9db47SJiri Pirko default: 252f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 253f9d9db47SJiri Pirko return -EINVAL; 254f9d9db47SJiri Pirko } 255f9d9db47SJiri Pirko 256f9d9db47SJiri Pirko err = -ENOENT; 257f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 258f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 259f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 260f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 261f5cd2160STaehee Yoo return -EBUSY; 262f5cd2160STaehee Yoo } 263f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 264f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 265f9d9db47SJiri Pirko continue; 266f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 267f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 268f9d9db47SJiri Pirko err = 0; 269f9d9db47SJiri Pirko break; 270f9d9db47SJiri Pirko } 271f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 272f9d9db47SJiri Pirko return !err ? count : err; 273f9d9db47SJiri Pirko } 274f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 275f9d9db47SJiri Pirko 276f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 277f9d9db47SJiri Pirko &bus_attr_new_device.attr, 278f9d9db47SJiri Pirko &bus_attr_del_device.attr, 279f9d9db47SJiri Pirko NULL 280f9d9db47SJiri Pirko }; 281f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 282f9d9db47SJiri Pirko 2838320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 2848320d145SJiri Pirko { 2858320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2868320d145SJiri Pirko 2878320d145SJiri Pirko return nsim_dev_probe(nsim_bus_dev); 2888320d145SJiri Pirko } 2898320d145SJiri Pirko 2908320d145SJiri Pirko static int nsim_bus_remove(struct device *dev) 2918320d145SJiri Pirko { 2928320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2938320d145SJiri Pirko 2948320d145SJiri Pirko nsim_dev_remove(nsim_bus_dev); 2958320d145SJiri Pirko return 0; 2968320d145SJiri Pirko } 2978320d145SJiri Pirko 29869bbbdc5SYueHaibing static int nsim_num_vf(struct device *dev) 29940e4fe4cSJiri Pirko { 30040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 30140e4fe4cSJiri Pirko 30240e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 30340e4fe4cSJiri Pirko } 30440e4fe4cSJiri Pirko 30540e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 306925f5afeSJiri Pirko .name = DRV_NAME, 307925f5afeSJiri Pirko .dev_name = DRV_NAME, 308f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 3098320d145SJiri Pirko .probe = nsim_bus_probe, 3108320d145SJiri Pirko .remove = nsim_bus_remove, 311925f5afeSJiri Pirko .num_vf = nsim_num_vf, 312925f5afeSJiri Pirko }; 313925f5afeSJiri Pirko 314e05b2d14SJiri Pirko static struct nsim_bus_dev * 315e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count) 31640e4fe4cSJiri Pirko { 31740e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 31840e4fe4cSJiri Pirko int err; 31940e4fe4cSJiri Pirko 32040e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 32140e4fe4cSJiri Pirko if (!nsim_bus_dev) 32240e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 32340e4fe4cSJiri Pirko 324e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 32557ce9774SJiri Pirko if (err < 0) 32657ce9774SJiri Pirko goto err_nsim_bus_dev_free; 32757ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 32840e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 32940e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 330f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 3317b60027bSJiri Pirko nsim_bus_dev->initial_net = current->nsproxy->net_ns; 332*6ab63366STaehee Yoo mutex_init(&nsim_bus_dev->nsim_bus_reload_lock); 333f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 334f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 335f9d9db47SJiri Pirko 33640e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 33740e4fe4cSJiri Pirko if (err) 33857ce9774SJiri Pirko goto err_nsim_bus_dev_id_free; 33940e4fe4cSJiri Pirko return nsim_bus_dev; 34040e4fe4cSJiri Pirko 34157ce9774SJiri Pirko err_nsim_bus_dev_id_free: 34257ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 34340e4fe4cSJiri Pirko err_nsim_bus_dev_free: 34440e4fe4cSJiri Pirko kfree(nsim_bus_dev); 34540e4fe4cSJiri Pirko return ERR_PTR(err); 34640e4fe4cSJiri Pirko } 34740e4fe4cSJiri Pirko 348e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 34940e4fe4cSJiri Pirko { 350f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 351f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 35240e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 35357ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 35440e4fe4cSJiri Pirko kfree(nsim_bus_dev); 35540e4fe4cSJiri Pirko } 35640e4fe4cSJiri Pirko 35723d415daSJiri Pirko static struct device_driver nsim_driver = { 35823d415daSJiri Pirko .name = DRV_NAME, 35923d415daSJiri Pirko .bus = &nsim_bus, 36023d415daSJiri Pirko .owner = THIS_MODULE, 36123d415daSJiri Pirko }; 36223d415daSJiri Pirko 363925f5afeSJiri Pirko int nsim_bus_init(void) 364925f5afeSJiri Pirko { 36523d415daSJiri Pirko int err; 36623d415daSJiri Pirko 36723d415daSJiri Pirko err = bus_register(&nsim_bus); 36823d415daSJiri Pirko if (err) 36923d415daSJiri Pirko return err; 37023d415daSJiri Pirko err = driver_register(&nsim_driver); 37123d415daSJiri Pirko if (err) 37223d415daSJiri Pirko goto err_bus_unregister; 373f5cd2160STaehee Yoo /* Allow using resources */ 374f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, true); 37523d415daSJiri Pirko return 0; 37623d415daSJiri Pirko 37723d415daSJiri Pirko err_bus_unregister: 37823d415daSJiri Pirko bus_unregister(&nsim_bus); 37923d415daSJiri Pirko return err; 380925f5afeSJiri Pirko } 381925f5afeSJiri Pirko 382925f5afeSJiri Pirko void nsim_bus_exit(void) 383925f5afeSJiri Pirko { 384f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 385f9d9db47SJiri Pirko 386f5cd2160STaehee Yoo /* Disallow using resources */ 387f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, false); 388f5cd2160STaehee Yoo 389f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 390f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 391f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 392f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 393f9d9db47SJiri Pirko } 394f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 395f5cd2160STaehee Yoo 39623d415daSJiri Pirko driver_unregister(&nsim_driver); 397925f5afeSJiri Pirko bus_unregister(&nsim_bus); 398925f5afeSJiri Pirko } 399