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 { 30*d3953819SDmytro Linkin if (nsim_bus_dev->max_vfs < num_vfs) 31*d3953819SDmytro Linkin return -ENOMEM; 32*d3953819SDmytro Linkin 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 nsim_bus_dev->num_vfs = 0; 4340e4fe4cSJiri Pirko } 4440e4fe4cSJiri Pirko 4540e4fe4cSJiri Pirko static ssize_t 4640e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 4740e4fe4cSJiri Pirko const char *buf, size_t count) 4840e4fe4cSJiri Pirko { 4940e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 5040e4fe4cSJiri Pirko unsigned int num_vfs; 5140e4fe4cSJiri Pirko int ret; 5240e4fe4cSJiri Pirko 5340e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 5440e4fe4cSJiri Pirko if (ret) 5540e4fe4cSJiri Pirko return ret; 5640e4fe4cSJiri Pirko 57*d3953819SDmytro Linkin mutex_lock(&nsim_bus_dev->vfs_lock); 5840e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs == num_vfs) 5940e4fe4cSJiri Pirko goto exit_good; 6040e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs && num_vfs) { 6140e4fe4cSJiri Pirko ret = -EBUSY; 6240e4fe4cSJiri Pirko goto exit_unlock; 6340e4fe4cSJiri Pirko } 6440e4fe4cSJiri Pirko 6540e4fe4cSJiri Pirko if (num_vfs) { 6640e4fe4cSJiri Pirko ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs); 6740e4fe4cSJiri Pirko if (ret) 6840e4fe4cSJiri Pirko goto exit_unlock; 6940e4fe4cSJiri Pirko } else { 7040e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 7140e4fe4cSJiri Pirko } 7240e4fe4cSJiri Pirko exit_good: 7340e4fe4cSJiri Pirko ret = count; 7440e4fe4cSJiri Pirko exit_unlock: 75*d3953819SDmytro Linkin mutex_unlock(&nsim_bus_dev->vfs_lock); 7640e4fe4cSJiri Pirko 7740e4fe4cSJiri Pirko return ret; 7840e4fe4cSJiri Pirko } 7940e4fe4cSJiri Pirko 8040e4fe4cSJiri Pirko static ssize_t 8140e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 8240e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 8340e4fe4cSJiri Pirko { 8440e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 8540e4fe4cSJiri Pirko 8640e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 8740e4fe4cSJiri Pirko } 8840e4fe4cSJiri Pirko 8940e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 9040e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 9140e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 9240e4fe4cSJiri Pirko 93*d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_read(struct file *file, 94*d3953819SDmytro Linkin char __user *data, 95*d3953819SDmytro Linkin size_t count, loff_t *ppos) 96*d3953819SDmytro Linkin { 97*d3953819SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = file->private_data; 98*d3953819SDmytro Linkin char buf[11]; 99*d3953819SDmytro Linkin size_t len; 100*d3953819SDmytro Linkin 101*d3953819SDmytro Linkin len = snprintf(buf, sizeof(buf), "%u\n", nsim_bus_dev->max_vfs); 102*d3953819SDmytro Linkin if (len < 0) 103*d3953819SDmytro Linkin return len; 104*d3953819SDmytro Linkin 105*d3953819SDmytro Linkin return simple_read_from_buffer(data, count, ppos, buf, len); 106*d3953819SDmytro Linkin } 107*d3953819SDmytro Linkin 108*d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_write(struct file *file, 109*d3953819SDmytro Linkin const char __user *data, 110*d3953819SDmytro Linkin size_t count, loff_t *ppos) 111*d3953819SDmytro Linkin { 112*d3953819SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = file->private_data; 113*d3953819SDmytro Linkin struct nsim_vf_config *vfconfigs; 114*d3953819SDmytro Linkin ssize_t ret; 115*d3953819SDmytro Linkin char buf[10]; 116*d3953819SDmytro Linkin u32 val; 117*d3953819SDmytro Linkin 118*d3953819SDmytro Linkin if (*ppos != 0) 119*d3953819SDmytro Linkin return 0; 120*d3953819SDmytro Linkin 121*d3953819SDmytro Linkin if (count >= sizeof(buf)) 122*d3953819SDmytro Linkin return -ENOSPC; 123*d3953819SDmytro Linkin 124*d3953819SDmytro Linkin mutex_lock(&nsim_bus_dev->vfs_lock); 125*d3953819SDmytro Linkin /* Reject if VFs are configured */ 126*d3953819SDmytro Linkin if (nsim_bus_dev->num_vfs) { 127*d3953819SDmytro Linkin ret = -EBUSY; 128*d3953819SDmytro Linkin goto unlock; 129*d3953819SDmytro Linkin } 130*d3953819SDmytro Linkin 131*d3953819SDmytro Linkin ret = copy_from_user(buf, data, count); 132*d3953819SDmytro Linkin if (ret) { 133*d3953819SDmytro Linkin ret = -EFAULT; 134*d3953819SDmytro Linkin goto unlock; 135*d3953819SDmytro Linkin } 136*d3953819SDmytro Linkin 137*d3953819SDmytro Linkin buf[count] = '\0'; 138*d3953819SDmytro Linkin ret = kstrtouint(buf, 10, &val); 139*d3953819SDmytro Linkin if (ret) { 140*d3953819SDmytro Linkin ret = -EIO; 141*d3953819SDmytro Linkin goto unlock; 142*d3953819SDmytro Linkin } 143*d3953819SDmytro Linkin 144*d3953819SDmytro Linkin vfconfigs = kcalloc(val, sizeof(struct nsim_vf_config), GFP_KERNEL | __GFP_NOWARN); 145*d3953819SDmytro Linkin if (!vfconfigs) { 146*d3953819SDmytro Linkin ret = -ENOMEM; 147*d3953819SDmytro Linkin goto unlock; 148*d3953819SDmytro Linkin } 149*d3953819SDmytro Linkin 150*d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 151*d3953819SDmytro Linkin nsim_bus_dev->vfconfigs = vfconfigs; 152*d3953819SDmytro Linkin nsim_bus_dev->max_vfs = val; 153*d3953819SDmytro Linkin *ppos += count; 154*d3953819SDmytro Linkin ret = count; 155*d3953819SDmytro Linkin unlock: 156*d3953819SDmytro Linkin mutex_unlock(&nsim_bus_dev->vfs_lock); 157*d3953819SDmytro Linkin return ret; 158*d3953819SDmytro Linkin } 159*d3953819SDmytro Linkin 160794b2c05SJiri Pirko static ssize_t 161794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 162794b2c05SJiri Pirko const char *buf, size_t count) 163794b2c05SJiri Pirko { 164794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 1656ab63366STaehee Yoo struct nsim_dev *nsim_dev = dev_get_drvdata(dev); 1666ab63366STaehee Yoo struct devlink *devlink; 167794b2c05SJiri Pirko unsigned int port_index; 168794b2c05SJiri Pirko int ret; 169794b2c05SJiri Pirko 170f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 171f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 172f5cd2160STaehee Yoo return -EBUSY; 173794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 174794b2c05SJiri Pirko if (ret) 175794b2c05SJiri Pirko return ret; 1766ab63366STaehee Yoo 1776ab63366STaehee Yoo devlink = priv_to_devlink(nsim_dev); 1786ab63366STaehee Yoo 1796ab63366STaehee Yoo mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 1806ab63366STaehee Yoo devlink_reload_disable(devlink); 181794b2c05SJiri Pirko ret = nsim_dev_port_add(nsim_bus_dev, port_index); 1826ab63366STaehee Yoo devlink_reload_enable(devlink); 1836ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 184794b2c05SJiri Pirko return ret ? ret : count; 185794b2c05SJiri Pirko } 186794b2c05SJiri Pirko 187794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 188794b2c05SJiri Pirko 189794b2c05SJiri Pirko static ssize_t 190794b2c05SJiri Pirko del_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); 1946ab63366STaehee Yoo struct nsim_dev *nsim_dev = dev_get_drvdata(dev); 1956ab63366STaehee Yoo struct devlink *devlink; 196794b2c05SJiri Pirko unsigned int port_index; 197794b2c05SJiri Pirko int ret; 198794b2c05SJiri Pirko 199f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 200f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 201f5cd2160STaehee Yoo return -EBUSY; 202794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 203794b2c05SJiri Pirko if (ret) 204794b2c05SJiri Pirko return ret; 2056ab63366STaehee Yoo 2066ab63366STaehee Yoo devlink = priv_to_devlink(nsim_dev); 2076ab63366STaehee Yoo 2086ab63366STaehee Yoo mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 2096ab63366STaehee Yoo devlink_reload_disable(devlink); 210794b2c05SJiri Pirko ret = nsim_dev_port_del(nsim_bus_dev, port_index); 2116ab63366STaehee Yoo devlink_reload_enable(devlink); 2126ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 213794b2c05SJiri Pirko return ret ? ret : count; 214794b2c05SJiri Pirko } 215794b2c05SJiri Pirko 216794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 217794b2c05SJiri Pirko 21840e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 21940e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 220794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 221794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 22240e4fe4cSJiri Pirko NULL, 22340e4fe4cSJiri Pirko }; 22440e4fe4cSJiri Pirko 22540e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 22640e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 22740e4fe4cSJiri Pirko }; 22840e4fe4cSJiri Pirko 22940e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 23040e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 23140e4fe4cSJiri Pirko NULL, 23240e4fe4cSJiri Pirko }; 23340e4fe4cSJiri Pirko 23440e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 23540e4fe4cSJiri Pirko { 23640e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 23740e4fe4cSJiri Pirko 23840e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 23940e4fe4cSJiri Pirko } 24040e4fe4cSJiri Pirko 24140e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 24240e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 24340e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 24440e4fe4cSJiri Pirko }; 24540e4fe4cSJiri Pirko 246e05b2d14SJiri Pirko static struct nsim_bus_dev * 247e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count); 248e05b2d14SJiri Pirko 249f9d9db47SJiri Pirko static ssize_t 250f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 251f9d9db47SJiri Pirko { 252f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 253f9d9db47SJiri Pirko unsigned int port_count; 254f9d9db47SJiri Pirko unsigned int id; 255f9d9db47SJiri Pirko int err; 256f9d9db47SJiri Pirko 257f9d9db47SJiri Pirko err = sscanf(buf, "%u %u", &id, &port_count); 258f9d9db47SJiri Pirko switch (err) { 259f9d9db47SJiri Pirko case 1: 260f9d9db47SJiri Pirko port_count = 1; 261df561f66SGustavo A. R. Silva fallthrough; 262f9d9db47SJiri Pirko case 2: 263f9d9db47SJiri Pirko if (id > INT_MAX) { 264f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 265f9d9db47SJiri Pirko return -EINVAL; 266f9d9db47SJiri Pirko } 267f9d9db47SJiri Pirko break; 268f9d9db47SJiri Pirko default: 269f9d9db47SJiri Pirko pr_err("Format for adding new device is \"id port_count\" (uint uint).\n"); 270f9d9db47SJiri Pirko return -EINVAL; 271f9d9db47SJiri Pirko } 272f9d9db47SJiri Pirko 273f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 274f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 275f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 276f5cd2160STaehee Yoo err = -EBUSY; 277f5cd2160STaehee Yoo goto err; 278f5cd2160STaehee Yoo } 279f5cd2160STaehee Yoo 280f5cd2160STaehee Yoo nsim_bus_dev = nsim_bus_dev_new(id, port_count); 281f5cd2160STaehee Yoo if (IS_ERR(nsim_bus_dev)) { 282f5cd2160STaehee Yoo err = PTR_ERR(nsim_bus_dev); 283f5cd2160STaehee Yoo goto err; 284f5cd2160STaehee Yoo } 285f5cd2160STaehee Yoo 286f5cd2160STaehee Yoo /* Allow using nsim_bus_dev */ 287f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, true); 288f5cd2160STaehee Yoo 289f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 290f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 291f9d9db47SJiri Pirko 292f9d9db47SJiri Pirko return count; 293f5cd2160STaehee Yoo err: 294f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 295f5cd2160STaehee Yoo return err; 296f9d9db47SJiri Pirko } 297f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 298f9d9db47SJiri Pirko 299e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 300e05b2d14SJiri Pirko 301f9d9db47SJiri Pirko static ssize_t 302f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 303f9d9db47SJiri Pirko { 304f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 305f9d9db47SJiri Pirko unsigned int id; 306f9d9db47SJiri Pirko int err; 307f9d9db47SJiri Pirko 308f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 309f9d9db47SJiri Pirko switch (err) { 310f9d9db47SJiri Pirko case 1: 311f9d9db47SJiri Pirko if (id > INT_MAX) { 312f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 313f9d9db47SJiri Pirko return -EINVAL; 314f9d9db47SJiri Pirko } 315f9d9db47SJiri Pirko break; 316f9d9db47SJiri Pirko default: 317f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 318f9d9db47SJiri Pirko return -EINVAL; 319f9d9db47SJiri Pirko } 320f9d9db47SJiri Pirko 321f9d9db47SJiri Pirko err = -ENOENT; 322f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 323f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 324f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 325f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 326f5cd2160STaehee Yoo return -EBUSY; 327f5cd2160STaehee Yoo } 328f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 329f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 330f9d9db47SJiri Pirko continue; 331f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 332f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 333f9d9db47SJiri Pirko err = 0; 334f9d9db47SJiri Pirko break; 335f9d9db47SJiri Pirko } 336f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 337f9d9db47SJiri Pirko return !err ? count : err; 338f9d9db47SJiri Pirko } 339f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 340f9d9db47SJiri Pirko 341f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 342f9d9db47SJiri Pirko &bus_attr_new_device.attr, 343f9d9db47SJiri Pirko &bus_attr_del_device.attr, 344f9d9db47SJiri Pirko NULL 345f9d9db47SJiri Pirko }; 346f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 347f9d9db47SJiri Pirko 3488320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 3498320d145SJiri Pirko { 3508320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3518320d145SJiri Pirko 3528320d145SJiri Pirko return nsim_dev_probe(nsim_bus_dev); 3538320d145SJiri Pirko } 3548320d145SJiri Pirko 3558320d145SJiri Pirko static int nsim_bus_remove(struct device *dev) 3568320d145SJiri Pirko { 3578320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3588320d145SJiri Pirko 3598320d145SJiri Pirko nsim_dev_remove(nsim_bus_dev); 3608320d145SJiri Pirko return 0; 3618320d145SJiri Pirko } 3628320d145SJiri Pirko 36369bbbdc5SYueHaibing static int nsim_num_vf(struct device *dev) 36440e4fe4cSJiri Pirko { 36540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 36640e4fe4cSJiri Pirko 36740e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 36840e4fe4cSJiri Pirko } 36940e4fe4cSJiri Pirko 37040e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 371925f5afeSJiri Pirko .name = DRV_NAME, 372925f5afeSJiri Pirko .dev_name = DRV_NAME, 373f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 3748320d145SJiri Pirko .probe = nsim_bus_probe, 3758320d145SJiri Pirko .remove = nsim_bus_remove, 376925f5afeSJiri Pirko .num_vf = nsim_num_vf, 377925f5afeSJiri Pirko }; 378925f5afeSJiri Pirko 379*d3953819SDmytro Linkin #define NSIM_BUS_DEV_MAX_VFS 4 380*d3953819SDmytro Linkin 381e05b2d14SJiri Pirko static struct nsim_bus_dev * 382e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count) 38340e4fe4cSJiri Pirko { 38440e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 38540e4fe4cSJiri Pirko int err; 38640e4fe4cSJiri Pirko 38740e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 38840e4fe4cSJiri Pirko if (!nsim_bus_dev) 38940e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 39040e4fe4cSJiri Pirko 391e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 39257ce9774SJiri Pirko if (err < 0) 39357ce9774SJiri Pirko goto err_nsim_bus_dev_free; 39457ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 39540e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 39640e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 397f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 3987b60027bSJiri Pirko nsim_bus_dev->initial_net = current->nsproxy->net_ns; 399*d3953819SDmytro Linkin nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS; 4006ab63366STaehee Yoo mutex_init(&nsim_bus_dev->nsim_bus_reload_lock); 401*d3953819SDmytro Linkin mutex_init(&nsim_bus_dev->vfs_lock); 402f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 403f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 404f9d9db47SJiri Pirko 405*d3953819SDmytro Linkin nsim_bus_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 406*d3953819SDmytro Linkin sizeof(struct nsim_vf_config), 407*d3953819SDmytro Linkin GFP_KERNEL | __GFP_NOWARN); 408*d3953819SDmytro Linkin if (!nsim_bus_dev->vfconfigs) { 409*d3953819SDmytro Linkin err = -ENOMEM; 410*d3953819SDmytro Linkin goto err_nsim_bus_dev_id_free; 411*d3953819SDmytro Linkin } 412*d3953819SDmytro Linkin 41340e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 41440e4fe4cSJiri Pirko if (err) 415*d3953819SDmytro Linkin goto err_nsim_vfs_free; 416*d3953819SDmytro Linkin 41740e4fe4cSJiri Pirko return nsim_bus_dev; 41840e4fe4cSJiri Pirko 419*d3953819SDmytro Linkin err_nsim_vfs_free: 420*d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 42157ce9774SJiri Pirko err_nsim_bus_dev_id_free: 42257ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 42340e4fe4cSJiri Pirko err_nsim_bus_dev_free: 42440e4fe4cSJiri Pirko kfree(nsim_bus_dev); 42540e4fe4cSJiri Pirko return ERR_PTR(err); 42640e4fe4cSJiri Pirko } 42740e4fe4cSJiri Pirko 428e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 42940e4fe4cSJiri Pirko { 430f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 431f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 43240e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 43357ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 434*d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 43540e4fe4cSJiri Pirko kfree(nsim_bus_dev); 43640e4fe4cSJiri Pirko } 43740e4fe4cSJiri Pirko 43823d415daSJiri Pirko static struct device_driver nsim_driver = { 43923d415daSJiri Pirko .name = DRV_NAME, 44023d415daSJiri Pirko .bus = &nsim_bus, 44123d415daSJiri Pirko .owner = THIS_MODULE, 44223d415daSJiri Pirko }; 44323d415daSJiri Pirko 444925f5afeSJiri Pirko int nsim_bus_init(void) 445925f5afeSJiri Pirko { 44623d415daSJiri Pirko int err; 44723d415daSJiri Pirko 44823d415daSJiri Pirko err = bus_register(&nsim_bus); 44923d415daSJiri Pirko if (err) 45023d415daSJiri Pirko return err; 45123d415daSJiri Pirko err = driver_register(&nsim_driver); 45223d415daSJiri Pirko if (err) 45323d415daSJiri Pirko goto err_bus_unregister; 454f5cd2160STaehee Yoo /* Allow using resources */ 455f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, true); 45623d415daSJiri Pirko return 0; 45723d415daSJiri Pirko 45823d415daSJiri Pirko err_bus_unregister: 45923d415daSJiri Pirko bus_unregister(&nsim_bus); 46023d415daSJiri Pirko return err; 461925f5afeSJiri Pirko } 462925f5afeSJiri Pirko 463925f5afeSJiri Pirko void nsim_bus_exit(void) 464925f5afeSJiri Pirko { 465f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 466f9d9db47SJiri Pirko 467f5cd2160STaehee Yoo /* Disallow using resources */ 468f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, false); 469f5cd2160STaehee Yoo 470f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 471f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 472f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 473f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 474f9d9db47SJiri Pirko } 475f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 476f5cd2160STaehee Yoo 47723d415daSJiri Pirko driver_unregister(&nsim_driver); 478925f5afeSJiri Pirko bus_unregister(&nsim_bus); 479925f5afeSJiri Pirko } 480