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 2726c37d89SJakub Kicinski static void 2826c37d89SJakub Kicinski nsim_bus_dev_set_vfs(struct nsim_bus_dev *nsim_bus_dev, unsigned int num_vfs) 2926c37d89SJakub Kicinski { 3026c37d89SJakub Kicinski rtnl_lock(); 3126c37d89SJakub Kicinski nsim_bus_dev->num_vfs = num_vfs; 3226c37d89SJakub Kicinski rtnl_unlock(); 3326c37d89SJakub Kicinski } 3426c37d89SJakub Kicinski 3540e4fe4cSJiri Pirko static int nsim_bus_dev_vfs_enable(struct nsim_bus_dev *nsim_bus_dev, 3640e4fe4cSJiri Pirko unsigned int num_vfs) 3740e4fe4cSJiri Pirko { 38160dc373SDmytro Linkin struct nsim_dev *nsim_dev; 39160dc373SDmytro Linkin int err = 0; 40160dc373SDmytro Linkin 41d3953819SDmytro Linkin if (nsim_bus_dev->max_vfs < num_vfs) 42d3953819SDmytro Linkin return -ENOMEM; 4326c37d89SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, num_vfs); 4440e4fe4cSJiri Pirko 45160dc373SDmytro Linkin nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 46160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(nsim_dev)) { 47160dc373SDmytro Linkin err = nsim_esw_switchdev_enable(nsim_dev, NULL); 48160dc373SDmytro Linkin if (err) 4926c37d89SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 50160dc373SDmytro Linkin } 51160dc373SDmytro Linkin 52160dc373SDmytro Linkin return err; 5340e4fe4cSJiri Pirko } 5440e4fe4cSJiri Pirko 5532ac15d8SDmytro Linkin void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev) 5640e4fe4cSJiri Pirko { 57160dc373SDmytro Linkin struct nsim_dev *nsim_dev; 58160dc373SDmytro Linkin 5926c37d89SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 60160dc373SDmytro Linkin nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 61160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(nsim_dev)) 62160dc373SDmytro Linkin nsim_esw_legacy_enable(nsim_dev, NULL); 6340e4fe4cSJiri Pirko } 6440e4fe4cSJiri Pirko 6540e4fe4cSJiri Pirko static ssize_t 6640e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 6740e4fe4cSJiri Pirko const char *buf, size_t count) 6840e4fe4cSJiri Pirko { 6940e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 70*5e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(dev); 7140e4fe4cSJiri Pirko unsigned int num_vfs; 7240e4fe4cSJiri Pirko int ret; 7340e4fe4cSJiri Pirko 7440e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 7540e4fe4cSJiri Pirko if (ret) 7640e4fe4cSJiri Pirko return ret; 7740e4fe4cSJiri Pirko 78*5e388f3dSJakub Kicinski device_lock(dev); 79*5e388f3dSJakub Kicinski if (!nsim_dev) { 80*5e388f3dSJakub Kicinski ret = -ENOENT; 81*5e388f3dSJakub Kicinski goto exit_unlock; 82*5e388f3dSJakub Kicinski } 83*5e388f3dSJakub Kicinski 84*5e388f3dSJakub Kicinski mutex_lock(&nsim_dev->vfs_lock); 8540e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs == num_vfs) 8640e4fe4cSJiri Pirko goto exit_good; 8740e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs && num_vfs) { 8840e4fe4cSJiri Pirko ret = -EBUSY; 8940e4fe4cSJiri Pirko goto exit_unlock; 9040e4fe4cSJiri Pirko } 9140e4fe4cSJiri Pirko 9240e4fe4cSJiri Pirko if (num_vfs) { 9340e4fe4cSJiri Pirko ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs); 9440e4fe4cSJiri Pirko if (ret) 9540e4fe4cSJiri Pirko goto exit_unlock; 9640e4fe4cSJiri Pirko } else { 9740e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 9840e4fe4cSJiri Pirko } 9940e4fe4cSJiri Pirko exit_good: 10040e4fe4cSJiri Pirko ret = count; 10140e4fe4cSJiri Pirko exit_unlock: 102*5e388f3dSJakub Kicinski mutex_unlock(&nsim_dev->vfs_lock); 103*5e388f3dSJakub Kicinski device_unlock(dev); 10440e4fe4cSJiri Pirko 10540e4fe4cSJiri Pirko return ret; 10640e4fe4cSJiri Pirko } 10740e4fe4cSJiri Pirko 10840e4fe4cSJiri Pirko static ssize_t 10940e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 11040e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 11140e4fe4cSJiri Pirko { 11240e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 11340e4fe4cSJiri Pirko 11440e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 11540e4fe4cSJiri Pirko } 11640e4fe4cSJiri Pirko 11740e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 11840e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 11940e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 12040e4fe4cSJiri Pirko 121d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_read(struct file *file, 122d3953819SDmytro Linkin char __user *data, 123d3953819SDmytro Linkin size_t count, loff_t *ppos) 124d3953819SDmytro Linkin { 125*5e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = file->private_data; 126*5e388f3dSJakub Kicinski struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 127d3953819SDmytro Linkin char buf[11]; 128ebbf5fcbSColin Ian King ssize_t len; 129d3953819SDmytro Linkin 130d3953819SDmytro Linkin len = snprintf(buf, sizeof(buf), "%u\n", nsim_bus_dev->max_vfs); 131d3953819SDmytro Linkin if (len < 0) 132d3953819SDmytro Linkin return len; 133d3953819SDmytro Linkin 134d3953819SDmytro Linkin return simple_read_from_buffer(data, count, ppos, buf, len); 135d3953819SDmytro Linkin } 136d3953819SDmytro Linkin 137d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_write(struct file *file, 138d3953819SDmytro Linkin const char __user *data, 139d3953819SDmytro Linkin size_t count, loff_t *ppos) 140d3953819SDmytro Linkin { 141*5e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = file->private_data; 142*5e388f3dSJakub Kicinski struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 143d3953819SDmytro Linkin struct nsim_vf_config *vfconfigs; 144d3953819SDmytro Linkin ssize_t ret; 145d3953819SDmytro Linkin char buf[10]; 146d3953819SDmytro Linkin u32 val; 147d3953819SDmytro Linkin 148d3953819SDmytro Linkin if (*ppos != 0) 149d3953819SDmytro Linkin return 0; 150d3953819SDmytro Linkin 151d3953819SDmytro Linkin if (count >= sizeof(buf)) 152d3953819SDmytro Linkin return -ENOSPC; 153d3953819SDmytro Linkin 154*5e388f3dSJakub Kicinski mutex_lock(&nsim_dev->vfs_lock); 155d3953819SDmytro Linkin /* Reject if VFs are configured */ 156d3953819SDmytro Linkin if (nsim_bus_dev->num_vfs) { 157d3953819SDmytro Linkin ret = -EBUSY; 158d3953819SDmytro Linkin goto unlock; 159d3953819SDmytro Linkin } 160d3953819SDmytro Linkin 161d3953819SDmytro Linkin ret = copy_from_user(buf, data, count); 162d3953819SDmytro Linkin if (ret) { 163d3953819SDmytro Linkin ret = -EFAULT; 164d3953819SDmytro Linkin goto unlock; 165d3953819SDmytro Linkin } 166d3953819SDmytro Linkin 167d3953819SDmytro Linkin buf[count] = '\0'; 168d3953819SDmytro Linkin ret = kstrtouint(buf, 10, &val); 169d3953819SDmytro Linkin if (ret) { 170d3953819SDmytro Linkin ret = -EIO; 171d3953819SDmytro Linkin goto unlock; 172d3953819SDmytro Linkin } 173d3953819SDmytro Linkin 174814b9ce6SDmytro Linkin /* max_vfs limited by the maximum number of provided port indexes */ 175814b9ce6SDmytro Linkin if (val > NSIM_DEV_VF_PORT_INDEX_MAX - NSIM_DEV_VF_PORT_INDEX_BASE) { 176814b9ce6SDmytro Linkin ret = -ERANGE; 177814b9ce6SDmytro Linkin goto unlock; 178814b9ce6SDmytro Linkin } 179814b9ce6SDmytro Linkin 180d3953819SDmytro Linkin vfconfigs = kcalloc(val, sizeof(struct nsim_vf_config), GFP_KERNEL | __GFP_NOWARN); 181d3953819SDmytro Linkin if (!vfconfigs) { 182d3953819SDmytro Linkin ret = -ENOMEM; 183d3953819SDmytro Linkin goto unlock; 184d3953819SDmytro Linkin } 185d3953819SDmytro Linkin 186*5e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 187*5e388f3dSJakub Kicinski nsim_dev->vfconfigs = vfconfigs; 188d3953819SDmytro Linkin nsim_bus_dev->max_vfs = val; 189d3953819SDmytro Linkin *ppos += count; 190d3953819SDmytro Linkin ret = count; 191d3953819SDmytro Linkin unlock: 192*5e388f3dSJakub Kicinski mutex_unlock(&nsim_dev->vfs_lock); 193d3953819SDmytro Linkin return ret; 194d3953819SDmytro Linkin } 195d3953819SDmytro Linkin 196794b2c05SJiri Pirko static ssize_t 197794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 198794b2c05SJiri Pirko const char *buf, size_t count) 199794b2c05SJiri Pirko { 200794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 201794b2c05SJiri Pirko unsigned int port_index; 202794b2c05SJiri Pirko int ret; 203794b2c05SJiri Pirko 204f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 205f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 206f5cd2160STaehee Yoo return -EBUSY; 207794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 208794b2c05SJiri Pirko if (ret) 209794b2c05SJiri Pirko return ret; 2106ab63366STaehee Yoo 21123809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 21223809a72SLeon Romanovsky return -EBUSY; 2136ab63366STaehee Yoo 2145c0418edSLeon Romanovsky if (nsim_bus_dev->in_reload) { 2155c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 2165c0418edSLeon Romanovsky return -EBUSY; 2175c0418edSLeon Romanovsky } 2185c0418edSLeon Romanovsky 219814b9ce6SDmytro Linkin ret = nsim_dev_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 2206ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 221794b2c05SJiri Pirko return ret ? ret : count; 222794b2c05SJiri Pirko } 223794b2c05SJiri Pirko 224794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 225794b2c05SJiri Pirko 226794b2c05SJiri Pirko static ssize_t 227794b2c05SJiri Pirko del_port_store(struct device *dev, struct device_attribute *attr, 228794b2c05SJiri Pirko const char *buf, size_t count) 229794b2c05SJiri Pirko { 230794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 231794b2c05SJiri Pirko unsigned int port_index; 232794b2c05SJiri Pirko int ret; 233794b2c05SJiri Pirko 234f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 235f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 236f5cd2160STaehee Yoo return -EBUSY; 237794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 238794b2c05SJiri Pirko if (ret) 239794b2c05SJiri Pirko return ret; 2406ab63366STaehee Yoo 24123809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 24223809a72SLeon Romanovsky return -EBUSY; 2436ab63366STaehee Yoo 2445c0418edSLeon Romanovsky if (nsim_bus_dev->in_reload) { 2455c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 2465c0418edSLeon Romanovsky return -EBUSY; 2475c0418edSLeon Romanovsky } 2485c0418edSLeon Romanovsky 249814b9ce6SDmytro Linkin ret = nsim_dev_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 2506ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 251794b2c05SJiri Pirko return ret ? ret : count; 252794b2c05SJiri Pirko } 253794b2c05SJiri Pirko 254794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 255794b2c05SJiri Pirko 25640e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 25740e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 258794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 259794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 26040e4fe4cSJiri Pirko NULL, 26140e4fe4cSJiri Pirko }; 26240e4fe4cSJiri Pirko 26340e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 26440e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 26540e4fe4cSJiri Pirko }; 26640e4fe4cSJiri Pirko 26740e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 26840e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 26940e4fe4cSJiri Pirko NULL, 27040e4fe4cSJiri Pirko }; 27140e4fe4cSJiri Pirko 27240e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 27340e4fe4cSJiri Pirko { 27440e4fe4cSJiri Pirko } 27540e4fe4cSJiri Pirko 27640e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 27740e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 27840e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 27940e4fe4cSJiri Pirko }; 28040e4fe4cSJiri Pirko 281e05b2d14SJiri Pirko static struct nsim_bus_dev * 282d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues); 283e05b2d14SJiri Pirko 284f9d9db47SJiri Pirko static ssize_t 285f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 286f9d9db47SJiri Pirko { 287d4861fc6SPeilin Ye unsigned int id, port_count, num_queues; 288f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 289f9d9db47SJiri Pirko int err; 290f9d9db47SJiri Pirko 291d4861fc6SPeilin Ye err = sscanf(buf, "%u %u %u", &id, &port_count, &num_queues); 292f9d9db47SJiri Pirko switch (err) { 293f9d9db47SJiri Pirko case 1: 294f9d9db47SJiri Pirko port_count = 1; 295df561f66SGustavo A. R. Silva fallthrough; 296f9d9db47SJiri Pirko case 2: 297d4861fc6SPeilin Ye num_queues = 1; 298d4861fc6SPeilin Ye fallthrough; 299d4861fc6SPeilin Ye case 3: 300f9d9db47SJiri Pirko if (id > INT_MAX) { 301f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 302f9d9db47SJiri Pirko return -EINVAL; 303f9d9db47SJiri Pirko } 304f9d9db47SJiri Pirko break; 305f9d9db47SJiri Pirko default: 306d4861fc6SPeilin Ye pr_err("Format for adding new device is \"id port_count num_queues\" (uint uint unit).\n"); 307f9d9db47SJiri Pirko return -EINVAL; 308f9d9db47SJiri Pirko } 309f9d9db47SJiri Pirko 310f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 311f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 312f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 313f5cd2160STaehee Yoo err = -EBUSY; 314f5cd2160STaehee Yoo goto err; 315f5cd2160STaehee Yoo } 316f5cd2160STaehee Yoo 317d4861fc6SPeilin Ye nsim_bus_dev = nsim_bus_dev_new(id, port_count, num_queues); 318f5cd2160STaehee Yoo if (IS_ERR(nsim_bus_dev)) { 319f5cd2160STaehee Yoo err = PTR_ERR(nsim_bus_dev); 320f5cd2160STaehee Yoo goto err; 321f5cd2160STaehee Yoo } 322f5cd2160STaehee Yoo 323f5cd2160STaehee Yoo /* Allow using nsim_bus_dev */ 324f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, true); 325f5cd2160STaehee Yoo 326f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 327f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 328f9d9db47SJiri Pirko 329f9d9db47SJiri Pirko return count; 330f5cd2160STaehee Yoo err: 331f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 332f5cd2160STaehee Yoo return err; 333f9d9db47SJiri Pirko } 334f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 335f9d9db47SJiri Pirko 336e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 337e05b2d14SJiri Pirko 338f9d9db47SJiri Pirko static ssize_t 339f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 340f9d9db47SJiri Pirko { 341f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 342f9d9db47SJiri Pirko unsigned int id; 343f9d9db47SJiri Pirko int err; 344f9d9db47SJiri Pirko 345f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 346f9d9db47SJiri Pirko switch (err) { 347f9d9db47SJiri Pirko case 1: 348f9d9db47SJiri Pirko if (id > INT_MAX) { 349f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 350f9d9db47SJiri Pirko return -EINVAL; 351f9d9db47SJiri Pirko } 352f9d9db47SJiri Pirko break; 353f9d9db47SJiri Pirko default: 354f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 355f9d9db47SJiri Pirko return -EINVAL; 356f9d9db47SJiri Pirko } 357f9d9db47SJiri Pirko 358f9d9db47SJiri Pirko err = -ENOENT; 359f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 360f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 361f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 362f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 363f5cd2160STaehee Yoo return -EBUSY; 364f5cd2160STaehee Yoo } 365f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 366f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 367f9d9db47SJiri Pirko continue; 368f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 369f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 370f9d9db47SJiri Pirko err = 0; 371f9d9db47SJiri Pirko break; 372f9d9db47SJiri Pirko } 373f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 374f9d9db47SJiri Pirko return !err ? count : err; 375f9d9db47SJiri Pirko } 376f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 377f9d9db47SJiri Pirko 378f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 379f9d9db47SJiri Pirko &bus_attr_new_device.attr, 380f9d9db47SJiri Pirko &bus_attr_del_device.attr, 381f9d9db47SJiri Pirko NULL 382f9d9db47SJiri Pirko }; 383f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 384f9d9db47SJiri Pirko 3858320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 3868320d145SJiri Pirko { 3878320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3888320d145SJiri Pirko 3898320d145SJiri Pirko return nsim_dev_probe(nsim_bus_dev); 3908320d145SJiri Pirko } 3918320d145SJiri Pirko 392fc7a6209SUwe Kleine-König static void nsim_bus_remove(struct device *dev) 3938320d145SJiri Pirko { 3948320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3958320d145SJiri Pirko 3968320d145SJiri Pirko nsim_dev_remove(nsim_bus_dev); 3978320d145SJiri Pirko } 3988320d145SJiri Pirko 39969bbbdc5SYueHaibing static int nsim_num_vf(struct device *dev) 40040e4fe4cSJiri Pirko { 40140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 40240e4fe4cSJiri Pirko 40340e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 40440e4fe4cSJiri Pirko } 40540e4fe4cSJiri Pirko 40640e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 407925f5afeSJiri Pirko .name = DRV_NAME, 408925f5afeSJiri Pirko .dev_name = DRV_NAME, 409f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 4108320d145SJiri Pirko .probe = nsim_bus_probe, 4118320d145SJiri Pirko .remove = nsim_bus_remove, 412925f5afeSJiri Pirko .num_vf = nsim_num_vf, 413925f5afeSJiri Pirko }; 414925f5afeSJiri Pirko 415d3953819SDmytro Linkin #define NSIM_BUS_DEV_MAX_VFS 4 416d3953819SDmytro Linkin 417e05b2d14SJiri Pirko static struct nsim_bus_dev * 418d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues) 41940e4fe4cSJiri Pirko { 42040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 42140e4fe4cSJiri Pirko int err; 42240e4fe4cSJiri Pirko 42340e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 42440e4fe4cSJiri Pirko if (!nsim_bus_dev) 42540e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 42640e4fe4cSJiri Pirko 427e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 42857ce9774SJiri Pirko if (err < 0) 42957ce9774SJiri Pirko goto err_nsim_bus_dev_free; 43057ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 43140e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 43240e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 433f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 434d4861fc6SPeilin Ye nsim_bus_dev->num_queues = num_queues; 4357b60027bSJiri Pirko nsim_bus_dev->initial_net = current->nsproxy->net_ns; 436d3953819SDmytro Linkin nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS; 4376ab63366STaehee Yoo mutex_init(&nsim_bus_dev->nsim_bus_reload_lock); 438f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 439f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 440f9d9db47SJiri Pirko 44140e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 44240e4fe4cSJiri Pirko if (err) 443*5e388f3dSJakub Kicinski goto err_nsim_bus_dev_id_free; 444d3953819SDmytro Linkin 44540e4fe4cSJiri Pirko return nsim_bus_dev; 44640e4fe4cSJiri Pirko 44757ce9774SJiri Pirko err_nsim_bus_dev_id_free: 44857ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 44940e4fe4cSJiri Pirko err_nsim_bus_dev_free: 45040e4fe4cSJiri Pirko kfree(nsim_bus_dev); 45140e4fe4cSJiri Pirko return ERR_PTR(err); 45240e4fe4cSJiri Pirko } 45340e4fe4cSJiri Pirko 454e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 45540e4fe4cSJiri Pirko { 456f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 457f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 45840e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 45957ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 46040e4fe4cSJiri Pirko kfree(nsim_bus_dev); 46140e4fe4cSJiri Pirko } 46240e4fe4cSJiri Pirko 46323d415daSJiri Pirko static struct device_driver nsim_driver = { 46423d415daSJiri Pirko .name = DRV_NAME, 46523d415daSJiri Pirko .bus = &nsim_bus, 46623d415daSJiri Pirko .owner = THIS_MODULE, 46723d415daSJiri Pirko }; 46823d415daSJiri Pirko 469925f5afeSJiri Pirko int nsim_bus_init(void) 470925f5afeSJiri Pirko { 47123d415daSJiri Pirko int err; 47223d415daSJiri Pirko 47323d415daSJiri Pirko err = bus_register(&nsim_bus); 47423d415daSJiri Pirko if (err) 47523d415daSJiri Pirko return err; 47623d415daSJiri Pirko err = driver_register(&nsim_driver); 47723d415daSJiri Pirko if (err) 47823d415daSJiri Pirko goto err_bus_unregister; 479f5cd2160STaehee Yoo /* Allow using resources */ 480f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, true); 48123d415daSJiri Pirko return 0; 48223d415daSJiri Pirko 48323d415daSJiri Pirko err_bus_unregister: 48423d415daSJiri Pirko bus_unregister(&nsim_bus); 48523d415daSJiri Pirko return err; 486925f5afeSJiri Pirko } 487925f5afeSJiri Pirko 488925f5afeSJiri Pirko void nsim_bus_exit(void) 489925f5afeSJiri Pirko { 490f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 491f9d9db47SJiri Pirko 492f5cd2160STaehee Yoo /* Disallow using resources */ 493f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, false); 494f5cd2160STaehee Yoo 495f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 496f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 497f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 498f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 499f9d9db47SJiri Pirko } 500f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 501f5cd2160STaehee Yoo 50223d415daSJiri Pirko driver_unregister(&nsim_driver); 503925f5afeSJiri Pirko bus_unregister(&nsim_bus); 504925f5afeSJiri Pirko } 505