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 27*26c37d89SJakub Kicinski static void 28*26c37d89SJakub Kicinski nsim_bus_dev_set_vfs(struct nsim_bus_dev *nsim_bus_dev, unsigned int num_vfs) 29*26c37d89SJakub Kicinski { 30*26c37d89SJakub Kicinski rtnl_lock(); 31*26c37d89SJakub Kicinski nsim_bus_dev->num_vfs = num_vfs; 32*26c37d89SJakub Kicinski rtnl_unlock(); 33*26c37d89SJakub Kicinski } 34*26c37d89SJakub 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; 43d3953819SDmytro Linkin 4440e4fe4cSJiri Pirko if (!nsim_bus_dev->vfconfigs) 4540e4fe4cSJiri Pirko return -ENOMEM; 46*26c37d89SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, num_vfs); 4740e4fe4cSJiri Pirko 48160dc373SDmytro Linkin nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 49160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(nsim_dev)) { 50160dc373SDmytro Linkin err = nsim_esw_switchdev_enable(nsim_dev, NULL); 51160dc373SDmytro Linkin if (err) 52*26c37d89SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 53160dc373SDmytro Linkin } 54160dc373SDmytro Linkin 55160dc373SDmytro Linkin return err; 5640e4fe4cSJiri Pirko } 5740e4fe4cSJiri Pirko 5832ac15d8SDmytro Linkin void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev) 5940e4fe4cSJiri Pirko { 60160dc373SDmytro Linkin struct nsim_dev *nsim_dev; 61160dc373SDmytro Linkin 62*26c37d89SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 63160dc373SDmytro Linkin nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 64160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(nsim_dev)) 65160dc373SDmytro Linkin nsim_esw_legacy_enable(nsim_dev, NULL); 6640e4fe4cSJiri Pirko } 6740e4fe4cSJiri Pirko 6840e4fe4cSJiri Pirko static ssize_t 6940e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 7040e4fe4cSJiri Pirko const char *buf, size_t count) 7140e4fe4cSJiri Pirko { 7240e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 7340e4fe4cSJiri Pirko unsigned int num_vfs; 7440e4fe4cSJiri Pirko int ret; 7540e4fe4cSJiri Pirko 7640e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 7740e4fe4cSJiri Pirko if (ret) 7840e4fe4cSJiri Pirko return ret; 7940e4fe4cSJiri Pirko 80d3953819SDmytro Linkin mutex_lock(&nsim_bus_dev->vfs_lock); 8140e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs == num_vfs) 8240e4fe4cSJiri Pirko goto exit_good; 8340e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs && num_vfs) { 8440e4fe4cSJiri Pirko ret = -EBUSY; 8540e4fe4cSJiri Pirko goto exit_unlock; 8640e4fe4cSJiri Pirko } 8740e4fe4cSJiri Pirko 8840e4fe4cSJiri Pirko if (num_vfs) { 8940e4fe4cSJiri Pirko ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs); 9040e4fe4cSJiri Pirko if (ret) 9140e4fe4cSJiri Pirko goto exit_unlock; 9240e4fe4cSJiri Pirko } else { 9340e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 9440e4fe4cSJiri Pirko } 9540e4fe4cSJiri Pirko exit_good: 9640e4fe4cSJiri Pirko ret = count; 9740e4fe4cSJiri Pirko exit_unlock: 98d3953819SDmytro Linkin mutex_unlock(&nsim_bus_dev->vfs_lock); 9940e4fe4cSJiri Pirko 10040e4fe4cSJiri Pirko return ret; 10140e4fe4cSJiri Pirko } 10240e4fe4cSJiri Pirko 10340e4fe4cSJiri Pirko static ssize_t 10440e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 10540e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 10640e4fe4cSJiri Pirko { 10740e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 10840e4fe4cSJiri Pirko 10940e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 11040e4fe4cSJiri Pirko } 11140e4fe4cSJiri Pirko 11240e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 11340e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 11440e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 11540e4fe4cSJiri Pirko 116d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_read(struct file *file, 117d3953819SDmytro Linkin char __user *data, 118d3953819SDmytro Linkin size_t count, loff_t *ppos) 119d3953819SDmytro Linkin { 120d3953819SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = file->private_data; 121d3953819SDmytro Linkin char buf[11]; 122ebbf5fcbSColin Ian King ssize_t len; 123d3953819SDmytro Linkin 124d3953819SDmytro Linkin len = snprintf(buf, sizeof(buf), "%u\n", nsim_bus_dev->max_vfs); 125d3953819SDmytro Linkin if (len < 0) 126d3953819SDmytro Linkin return len; 127d3953819SDmytro Linkin 128d3953819SDmytro Linkin return simple_read_from_buffer(data, count, ppos, buf, len); 129d3953819SDmytro Linkin } 130d3953819SDmytro Linkin 131d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_write(struct file *file, 132d3953819SDmytro Linkin const char __user *data, 133d3953819SDmytro Linkin size_t count, loff_t *ppos) 134d3953819SDmytro Linkin { 135d3953819SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = file->private_data; 136d3953819SDmytro Linkin struct nsim_vf_config *vfconfigs; 137d3953819SDmytro Linkin ssize_t ret; 138d3953819SDmytro Linkin char buf[10]; 139d3953819SDmytro Linkin u32 val; 140d3953819SDmytro Linkin 141d3953819SDmytro Linkin if (*ppos != 0) 142d3953819SDmytro Linkin return 0; 143d3953819SDmytro Linkin 144d3953819SDmytro Linkin if (count >= sizeof(buf)) 145d3953819SDmytro Linkin return -ENOSPC; 146d3953819SDmytro Linkin 147d3953819SDmytro Linkin mutex_lock(&nsim_bus_dev->vfs_lock); 148d3953819SDmytro Linkin /* Reject if VFs are configured */ 149d3953819SDmytro Linkin if (nsim_bus_dev->num_vfs) { 150d3953819SDmytro Linkin ret = -EBUSY; 151d3953819SDmytro Linkin goto unlock; 152d3953819SDmytro Linkin } 153d3953819SDmytro Linkin 154d3953819SDmytro Linkin ret = copy_from_user(buf, data, count); 155d3953819SDmytro Linkin if (ret) { 156d3953819SDmytro Linkin ret = -EFAULT; 157d3953819SDmytro Linkin goto unlock; 158d3953819SDmytro Linkin } 159d3953819SDmytro Linkin 160d3953819SDmytro Linkin buf[count] = '\0'; 161d3953819SDmytro Linkin ret = kstrtouint(buf, 10, &val); 162d3953819SDmytro Linkin if (ret) { 163d3953819SDmytro Linkin ret = -EIO; 164d3953819SDmytro Linkin goto unlock; 165d3953819SDmytro Linkin } 166d3953819SDmytro Linkin 167814b9ce6SDmytro Linkin /* max_vfs limited by the maximum number of provided port indexes */ 168814b9ce6SDmytro Linkin if (val > NSIM_DEV_VF_PORT_INDEX_MAX - NSIM_DEV_VF_PORT_INDEX_BASE) { 169814b9ce6SDmytro Linkin ret = -ERANGE; 170814b9ce6SDmytro Linkin goto unlock; 171814b9ce6SDmytro Linkin } 172814b9ce6SDmytro Linkin 173d3953819SDmytro Linkin vfconfigs = kcalloc(val, sizeof(struct nsim_vf_config), GFP_KERNEL | __GFP_NOWARN); 174d3953819SDmytro Linkin if (!vfconfigs) { 175d3953819SDmytro Linkin ret = -ENOMEM; 176d3953819SDmytro Linkin goto unlock; 177d3953819SDmytro Linkin } 178d3953819SDmytro Linkin 179d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 180d3953819SDmytro Linkin nsim_bus_dev->vfconfigs = vfconfigs; 181d3953819SDmytro Linkin nsim_bus_dev->max_vfs = val; 182d3953819SDmytro Linkin *ppos += count; 183d3953819SDmytro Linkin ret = count; 184d3953819SDmytro Linkin unlock: 185d3953819SDmytro Linkin mutex_unlock(&nsim_bus_dev->vfs_lock); 186d3953819SDmytro Linkin return ret; 187d3953819SDmytro Linkin } 188d3953819SDmytro Linkin 189794b2c05SJiri Pirko static ssize_t 190794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 191794b2c05SJiri Pirko const char *buf, size_t count) 192794b2c05SJiri Pirko { 193794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 194794b2c05SJiri Pirko unsigned int port_index; 195794b2c05SJiri Pirko int ret; 196794b2c05SJiri Pirko 197f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 198f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 199f5cd2160STaehee Yoo return -EBUSY; 200794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 201794b2c05SJiri Pirko if (ret) 202794b2c05SJiri Pirko return ret; 2036ab63366STaehee Yoo 20423809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 20523809a72SLeon Romanovsky return -EBUSY; 2066ab63366STaehee Yoo 2075c0418edSLeon Romanovsky if (nsim_bus_dev->in_reload) { 2085c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 2095c0418edSLeon Romanovsky return -EBUSY; 2105c0418edSLeon Romanovsky } 2115c0418edSLeon Romanovsky 212814b9ce6SDmytro Linkin ret = nsim_dev_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 2136ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 214794b2c05SJiri Pirko return ret ? ret : count; 215794b2c05SJiri Pirko } 216794b2c05SJiri Pirko 217794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 218794b2c05SJiri Pirko 219794b2c05SJiri Pirko static ssize_t 220794b2c05SJiri Pirko del_port_store(struct device *dev, struct device_attribute *attr, 221794b2c05SJiri Pirko const char *buf, size_t count) 222794b2c05SJiri Pirko { 223794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 224794b2c05SJiri Pirko unsigned int port_index; 225794b2c05SJiri Pirko int ret; 226794b2c05SJiri Pirko 227f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 228f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 229f5cd2160STaehee Yoo return -EBUSY; 230794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 231794b2c05SJiri Pirko if (ret) 232794b2c05SJiri Pirko return ret; 2336ab63366STaehee Yoo 23423809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 23523809a72SLeon Romanovsky return -EBUSY; 2366ab63366STaehee Yoo 2375c0418edSLeon Romanovsky if (nsim_bus_dev->in_reload) { 2385c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 2395c0418edSLeon Romanovsky return -EBUSY; 2405c0418edSLeon Romanovsky } 2415c0418edSLeon Romanovsky 242814b9ce6SDmytro Linkin ret = nsim_dev_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 2436ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 244794b2c05SJiri Pirko return ret ? ret : count; 245794b2c05SJiri Pirko } 246794b2c05SJiri Pirko 247794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 248794b2c05SJiri Pirko 24940e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 25040e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 251794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 252794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 25340e4fe4cSJiri Pirko NULL, 25440e4fe4cSJiri Pirko }; 25540e4fe4cSJiri Pirko 25640e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 25740e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 25840e4fe4cSJiri Pirko }; 25940e4fe4cSJiri Pirko 26040e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 26140e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 26240e4fe4cSJiri Pirko NULL, 26340e4fe4cSJiri Pirko }; 26440e4fe4cSJiri Pirko 26540e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 26640e4fe4cSJiri Pirko { 26740e4fe4cSJiri Pirko } 26840e4fe4cSJiri Pirko 26940e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 27040e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 27140e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 27240e4fe4cSJiri Pirko }; 27340e4fe4cSJiri Pirko 274e05b2d14SJiri Pirko static struct nsim_bus_dev * 275d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues); 276e05b2d14SJiri Pirko 277f9d9db47SJiri Pirko static ssize_t 278f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 279f9d9db47SJiri Pirko { 280d4861fc6SPeilin Ye unsigned int id, port_count, num_queues; 281f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 282f9d9db47SJiri Pirko int err; 283f9d9db47SJiri Pirko 284d4861fc6SPeilin Ye err = sscanf(buf, "%u %u %u", &id, &port_count, &num_queues); 285f9d9db47SJiri Pirko switch (err) { 286f9d9db47SJiri Pirko case 1: 287f9d9db47SJiri Pirko port_count = 1; 288df561f66SGustavo A. R. Silva fallthrough; 289f9d9db47SJiri Pirko case 2: 290d4861fc6SPeilin Ye num_queues = 1; 291d4861fc6SPeilin Ye fallthrough; 292d4861fc6SPeilin Ye case 3: 293f9d9db47SJiri Pirko if (id > INT_MAX) { 294f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 295f9d9db47SJiri Pirko return -EINVAL; 296f9d9db47SJiri Pirko } 297f9d9db47SJiri Pirko break; 298f9d9db47SJiri Pirko default: 299d4861fc6SPeilin Ye pr_err("Format for adding new device is \"id port_count num_queues\" (uint uint unit).\n"); 300f9d9db47SJiri Pirko return -EINVAL; 301f9d9db47SJiri Pirko } 302f9d9db47SJiri Pirko 303f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 304f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 305f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 306f5cd2160STaehee Yoo err = -EBUSY; 307f5cd2160STaehee Yoo goto err; 308f5cd2160STaehee Yoo } 309f5cd2160STaehee Yoo 310d4861fc6SPeilin Ye nsim_bus_dev = nsim_bus_dev_new(id, port_count, num_queues); 311f5cd2160STaehee Yoo if (IS_ERR(nsim_bus_dev)) { 312f5cd2160STaehee Yoo err = PTR_ERR(nsim_bus_dev); 313f5cd2160STaehee Yoo goto err; 314f5cd2160STaehee Yoo } 315f5cd2160STaehee Yoo 316f5cd2160STaehee Yoo /* Allow using nsim_bus_dev */ 317f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, true); 318f5cd2160STaehee Yoo 319f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 320f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 321f9d9db47SJiri Pirko 322f9d9db47SJiri Pirko return count; 323f5cd2160STaehee Yoo err: 324f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 325f5cd2160STaehee Yoo return err; 326f9d9db47SJiri Pirko } 327f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 328f9d9db47SJiri Pirko 329e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 330e05b2d14SJiri Pirko 331f9d9db47SJiri Pirko static ssize_t 332f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 333f9d9db47SJiri Pirko { 334f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 335f9d9db47SJiri Pirko unsigned int id; 336f9d9db47SJiri Pirko int err; 337f9d9db47SJiri Pirko 338f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 339f9d9db47SJiri Pirko switch (err) { 340f9d9db47SJiri Pirko case 1: 341f9d9db47SJiri Pirko if (id > INT_MAX) { 342f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 343f9d9db47SJiri Pirko return -EINVAL; 344f9d9db47SJiri Pirko } 345f9d9db47SJiri Pirko break; 346f9d9db47SJiri Pirko default: 347f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 348f9d9db47SJiri Pirko return -EINVAL; 349f9d9db47SJiri Pirko } 350f9d9db47SJiri Pirko 351f9d9db47SJiri Pirko err = -ENOENT; 352f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 353f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 354f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 355f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 356f5cd2160STaehee Yoo return -EBUSY; 357f5cd2160STaehee Yoo } 358f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 359f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 360f9d9db47SJiri Pirko continue; 361f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 362f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 363f9d9db47SJiri Pirko err = 0; 364f9d9db47SJiri Pirko break; 365f9d9db47SJiri Pirko } 366f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 367f9d9db47SJiri Pirko return !err ? count : err; 368f9d9db47SJiri Pirko } 369f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 370f9d9db47SJiri Pirko 371f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 372f9d9db47SJiri Pirko &bus_attr_new_device.attr, 373f9d9db47SJiri Pirko &bus_attr_del_device.attr, 374f9d9db47SJiri Pirko NULL 375f9d9db47SJiri Pirko }; 376f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 377f9d9db47SJiri Pirko 3788320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 3798320d145SJiri Pirko { 3808320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3818320d145SJiri Pirko 3828320d145SJiri Pirko return nsim_dev_probe(nsim_bus_dev); 3838320d145SJiri Pirko } 3848320d145SJiri Pirko 385fc7a6209SUwe Kleine-König static void nsim_bus_remove(struct device *dev) 3868320d145SJiri Pirko { 3878320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3888320d145SJiri Pirko 3898320d145SJiri Pirko nsim_dev_remove(nsim_bus_dev); 3908320d145SJiri Pirko } 3918320d145SJiri Pirko 39269bbbdc5SYueHaibing static int nsim_num_vf(struct device *dev) 39340e4fe4cSJiri Pirko { 39440e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 39540e4fe4cSJiri Pirko 39640e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 39740e4fe4cSJiri Pirko } 39840e4fe4cSJiri Pirko 39940e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 400925f5afeSJiri Pirko .name = DRV_NAME, 401925f5afeSJiri Pirko .dev_name = DRV_NAME, 402f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 4038320d145SJiri Pirko .probe = nsim_bus_probe, 4048320d145SJiri Pirko .remove = nsim_bus_remove, 405925f5afeSJiri Pirko .num_vf = nsim_num_vf, 406925f5afeSJiri Pirko }; 407925f5afeSJiri Pirko 408d3953819SDmytro Linkin #define NSIM_BUS_DEV_MAX_VFS 4 409d3953819SDmytro Linkin 410e05b2d14SJiri Pirko static struct nsim_bus_dev * 411d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues) 41240e4fe4cSJiri Pirko { 41340e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 41440e4fe4cSJiri Pirko int err; 41540e4fe4cSJiri Pirko 41640e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 41740e4fe4cSJiri Pirko if (!nsim_bus_dev) 41840e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 41940e4fe4cSJiri Pirko 420e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 42157ce9774SJiri Pirko if (err < 0) 42257ce9774SJiri Pirko goto err_nsim_bus_dev_free; 42357ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 42440e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 42540e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 426f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 427d4861fc6SPeilin Ye nsim_bus_dev->num_queues = num_queues; 4287b60027bSJiri Pirko nsim_bus_dev->initial_net = current->nsproxy->net_ns; 429d3953819SDmytro Linkin nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS; 4306ab63366STaehee Yoo mutex_init(&nsim_bus_dev->nsim_bus_reload_lock); 431d3953819SDmytro Linkin mutex_init(&nsim_bus_dev->vfs_lock); 432f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 433f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 434f9d9db47SJiri Pirko 435d3953819SDmytro Linkin nsim_bus_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 436d3953819SDmytro Linkin sizeof(struct nsim_vf_config), 437d3953819SDmytro Linkin GFP_KERNEL | __GFP_NOWARN); 438d3953819SDmytro Linkin if (!nsim_bus_dev->vfconfigs) { 439d3953819SDmytro Linkin err = -ENOMEM; 440d3953819SDmytro Linkin goto err_nsim_bus_dev_id_free; 441d3953819SDmytro Linkin } 442d3953819SDmytro Linkin 44340e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 44440e4fe4cSJiri Pirko if (err) 445d3953819SDmytro Linkin goto err_nsim_vfs_free; 446d3953819SDmytro Linkin 44740e4fe4cSJiri Pirko return nsim_bus_dev; 44840e4fe4cSJiri Pirko 449d3953819SDmytro Linkin err_nsim_vfs_free: 450d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 45157ce9774SJiri Pirko err_nsim_bus_dev_id_free: 45257ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 45340e4fe4cSJiri Pirko err_nsim_bus_dev_free: 45440e4fe4cSJiri Pirko kfree(nsim_bus_dev); 45540e4fe4cSJiri Pirko return ERR_PTR(err); 45640e4fe4cSJiri Pirko } 45740e4fe4cSJiri Pirko 458e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 45940e4fe4cSJiri Pirko { 460f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 461f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 46240e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 46357ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 464d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 46540e4fe4cSJiri Pirko kfree(nsim_bus_dev); 46640e4fe4cSJiri Pirko } 46740e4fe4cSJiri Pirko 46823d415daSJiri Pirko static struct device_driver nsim_driver = { 46923d415daSJiri Pirko .name = DRV_NAME, 47023d415daSJiri Pirko .bus = &nsim_bus, 47123d415daSJiri Pirko .owner = THIS_MODULE, 47223d415daSJiri Pirko }; 47323d415daSJiri Pirko 474925f5afeSJiri Pirko int nsim_bus_init(void) 475925f5afeSJiri Pirko { 47623d415daSJiri Pirko int err; 47723d415daSJiri Pirko 47823d415daSJiri Pirko err = bus_register(&nsim_bus); 47923d415daSJiri Pirko if (err) 48023d415daSJiri Pirko return err; 48123d415daSJiri Pirko err = driver_register(&nsim_driver); 48223d415daSJiri Pirko if (err) 48323d415daSJiri Pirko goto err_bus_unregister; 484f5cd2160STaehee Yoo /* Allow using resources */ 485f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, true); 48623d415daSJiri Pirko return 0; 48723d415daSJiri Pirko 48823d415daSJiri Pirko err_bus_unregister: 48923d415daSJiri Pirko bus_unregister(&nsim_bus); 49023d415daSJiri Pirko return err; 491925f5afeSJiri Pirko } 492925f5afeSJiri Pirko 493925f5afeSJiri Pirko void nsim_bus_exit(void) 494925f5afeSJiri Pirko { 495f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 496f9d9db47SJiri Pirko 497f5cd2160STaehee Yoo /* Disallow using resources */ 498f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, false); 499f5cd2160STaehee Yoo 500f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 501f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 502f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 503f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 504f9d9db47SJiri Pirko } 505f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 506f5cd2160STaehee Yoo 50723d415daSJiri Pirko driver_unregister(&nsim_driver); 508925f5afeSJiri Pirko bus_unregister(&nsim_bus); 509925f5afeSJiri Pirko } 510