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 { 30160dc373SDmytro Linkin struct nsim_dev *nsim_dev; 31160dc373SDmytro Linkin int err = 0; 32160dc373SDmytro Linkin 33d3953819SDmytro Linkin if (nsim_bus_dev->max_vfs < num_vfs) 34d3953819SDmytro Linkin return -ENOMEM; 35d3953819SDmytro Linkin 3640e4fe4cSJiri Pirko if (!nsim_bus_dev->vfconfigs) 3740e4fe4cSJiri Pirko return -ENOMEM; 3840e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = num_vfs; 3940e4fe4cSJiri Pirko 40160dc373SDmytro Linkin nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 41160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(nsim_dev)) { 42160dc373SDmytro Linkin err = nsim_esw_switchdev_enable(nsim_dev, NULL); 43160dc373SDmytro Linkin if (err) 44160dc373SDmytro Linkin nsim_bus_dev->num_vfs = 0; 45160dc373SDmytro Linkin } 46160dc373SDmytro Linkin 47160dc373SDmytro Linkin return err; 4840e4fe4cSJiri Pirko } 4940e4fe4cSJiri Pirko 5032ac15d8SDmytro Linkin void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev) 5140e4fe4cSJiri Pirko { 52160dc373SDmytro Linkin struct nsim_dev *nsim_dev; 53160dc373SDmytro Linkin 5440e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = 0; 55160dc373SDmytro Linkin nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 56160dc373SDmytro Linkin if (nsim_esw_mode_is_switchdev(nsim_dev)) 57160dc373SDmytro Linkin nsim_esw_legacy_enable(nsim_dev, NULL); 5840e4fe4cSJiri Pirko } 5940e4fe4cSJiri Pirko 6040e4fe4cSJiri Pirko static ssize_t 6140e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 6240e4fe4cSJiri Pirko const char *buf, size_t count) 6340e4fe4cSJiri Pirko { 6440e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 6540e4fe4cSJiri Pirko unsigned int num_vfs; 6640e4fe4cSJiri Pirko int ret; 6740e4fe4cSJiri Pirko 6840e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 6940e4fe4cSJiri Pirko if (ret) 7040e4fe4cSJiri Pirko return ret; 7140e4fe4cSJiri Pirko 72d3953819SDmytro Linkin mutex_lock(&nsim_bus_dev->vfs_lock); 7340e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs == num_vfs) 7440e4fe4cSJiri Pirko goto exit_good; 7540e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs && num_vfs) { 7640e4fe4cSJiri Pirko ret = -EBUSY; 7740e4fe4cSJiri Pirko goto exit_unlock; 7840e4fe4cSJiri Pirko } 7940e4fe4cSJiri Pirko 8040e4fe4cSJiri Pirko if (num_vfs) { 8140e4fe4cSJiri Pirko ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs); 8240e4fe4cSJiri Pirko if (ret) 8340e4fe4cSJiri Pirko goto exit_unlock; 8440e4fe4cSJiri Pirko } else { 8540e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 8640e4fe4cSJiri Pirko } 8740e4fe4cSJiri Pirko exit_good: 8840e4fe4cSJiri Pirko ret = count; 8940e4fe4cSJiri Pirko exit_unlock: 90d3953819SDmytro Linkin mutex_unlock(&nsim_bus_dev->vfs_lock); 9140e4fe4cSJiri Pirko 9240e4fe4cSJiri Pirko return ret; 9340e4fe4cSJiri Pirko } 9440e4fe4cSJiri Pirko 9540e4fe4cSJiri Pirko static ssize_t 9640e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 9740e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 9840e4fe4cSJiri Pirko { 9940e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 10040e4fe4cSJiri Pirko 10140e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 10240e4fe4cSJiri Pirko } 10340e4fe4cSJiri Pirko 10440e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 10540e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 10640e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 10740e4fe4cSJiri Pirko 108d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_read(struct file *file, 109d3953819SDmytro Linkin char __user *data, 110d3953819SDmytro Linkin size_t count, loff_t *ppos) 111d3953819SDmytro Linkin { 112d3953819SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = file->private_data; 113d3953819SDmytro Linkin char buf[11]; 114ebbf5fcbSColin Ian King ssize_t len; 115d3953819SDmytro Linkin 116d3953819SDmytro Linkin len = snprintf(buf, sizeof(buf), "%u\n", nsim_bus_dev->max_vfs); 117d3953819SDmytro Linkin if (len < 0) 118d3953819SDmytro Linkin return len; 119d3953819SDmytro Linkin 120d3953819SDmytro Linkin return simple_read_from_buffer(data, count, ppos, buf, len); 121d3953819SDmytro Linkin } 122d3953819SDmytro Linkin 123d3953819SDmytro Linkin ssize_t nsim_bus_dev_max_vfs_write(struct file *file, 124d3953819SDmytro Linkin const char __user *data, 125d3953819SDmytro Linkin size_t count, loff_t *ppos) 126d3953819SDmytro Linkin { 127d3953819SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = file->private_data; 128d3953819SDmytro Linkin struct nsim_vf_config *vfconfigs; 129d3953819SDmytro Linkin ssize_t ret; 130d3953819SDmytro Linkin char buf[10]; 131d3953819SDmytro Linkin u32 val; 132d3953819SDmytro Linkin 133d3953819SDmytro Linkin if (*ppos != 0) 134d3953819SDmytro Linkin return 0; 135d3953819SDmytro Linkin 136d3953819SDmytro Linkin if (count >= sizeof(buf)) 137d3953819SDmytro Linkin return -ENOSPC; 138d3953819SDmytro Linkin 139d3953819SDmytro Linkin mutex_lock(&nsim_bus_dev->vfs_lock); 140d3953819SDmytro Linkin /* Reject if VFs are configured */ 141d3953819SDmytro Linkin if (nsim_bus_dev->num_vfs) { 142d3953819SDmytro Linkin ret = -EBUSY; 143d3953819SDmytro Linkin goto unlock; 144d3953819SDmytro Linkin } 145d3953819SDmytro Linkin 146d3953819SDmytro Linkin ret = copy_from_user(buf, data, count); 147d3953819SDmytro Linkin if (ret) { 148d3953819SDmytro Linkin ret = -EFAULT; 149d3953819SDmytro Linkin goto unlock; 150d3953819SDmytro Linkin } 151d3953819SDmytro Linkin 152d3953819SDmytro Linkin buf[count] = '\0'; 153d3953819SDmytro Linkin ret = kstrtouint(buf, 10, &val); 154d3953819SDmytro Linkin if (ret) { 155d3953819SDmytro Linkin ret = -EIO; 156d3953819SDmytro Linkin goto unlock; 157d3953819SDmytro Linkin } 158d3953819SDmytro Linkin 159814b9ce6SDmytro Linkin /* max_vfs limited by the maximum number of provided port indexes */ 160814b9ce6SDmytro Linkin if (val > NSIM_DEV_VF_PORT_INDEX_MAX - NSIM_DEV_VF_PORT_INDEX_BASE) { 161814b9ce6SDmytro Linkin ret = -ERANGE; 162814b9ce6SDmytro Linkin goto unlock; 163814b9ce6SDmytro Linkin } 164814b9ce6SDmytro Linkin 165d3953819SDmytro Linkin vfconfigs = kcalloc(val, sizeof(struct nsim_vf_config), GFP_KERNEL | __GFP_NOWARN); 166d3953819SDmytro Linkin if (!vfconfigs) { 167d3953819SDmytro Linkin ret = -ENOMEM; 168d3953819SDmytro Linkin goto unlock; 169d3953819SDmytro Linkin } 170d3953819SDmytro Linkin 171d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 172d3953819SDmytro Linkin nsim_bus_dev->vfconfigs = vfconfigs; 173d3953819SDmytro Linkin nsim_bus_dev->max_vfs = val; 174d3953819SDmytro Linkin *ppos += count; 175d3953819SDmytro Linkin ret = count; 176d3953819SDmytro Linkin unlock: 177d3953819SDmytro Linkin mutex_unlock(&nsim_bus_dev->vfs_lock); 178d3953819SDmytro Linkin return ret; 179d3953819SDmytro Linkin } 180d3953819SDmytro Linkin 181794b2c05SJiri Pirko static ssize_t 182794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 183794b2c05SJiri Pirko const char *buf, size_t count) 184794b2c05SJiri Pirko { 185794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 1866ab63366STaehee Yoo struct nsim_dev *nsim_dev = dev_get_drvdata(dev); 1876ab63366STaehee Yoo struct devlink *devlink; 188794b2c05SJiri Pirko unsigned int port_index; 189794b2c05SJiri Pirko int ret; 190794b2c05SJiri Pirko 191f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 192f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 193f5cd2160STaehee Yoo return -EBUSY; 194794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 195794b2c05SJiri Pirko if (ret) 196794b2c05SJiri Pirko return ret; 1976ab63366STaehee Yoo 1986ab63366STaehee Yoo devlink = priv_to_devlink(nsim_dev); 1996ab63366STaehee Yoo 2006ab63366STaehee Yoo mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 2016ab63366STaehee Yoo devlink_reload_disable(devlink); 202814b9ce6SDmytro Linkin ret = nsim_dev_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 2036ab63366STaehee Yoo devlink_reload_enable(devlink); 2046ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 205794b2c05SJiri Pirko return ret ? ret : count; 206794b2c05SJiri Pirko } 207794b2c05SJiri Pirko 208794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 209794b2c05SJiri Pirko 210794b2c05SJiri Pirko static ssize_t 211794b2c05SJiri Pirko del_port_store(struct device *dev, struct device_attribute *attr, 212794b2c05SJiri Pirko const char *buf, size_t count) 213794b2c05SJiri Pirko { 214794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2156ab63366STaehee Yoo struct nsim_dev *nsim_dev = dev_get_drvdata(dev); 2166ab63366STaehee Yoo struct devlink *devlink; 217794b2c05SJiri Pirko unsigned int port_index; 218794b2c05SJiri Pirko int ret; 219794b2c05SJiri Pirko 220f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 221f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 222f5cd2160STaehee Yoo return -EBUSY; 223794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 224794b2c05SJiri Pirko if (ret) 225794b2c05SJiri Pirko return ret; 2266ab63366STaehee Yoo 2276ab63366STaehee Yoo devlink = priv_to_devlink(nsim_dev); 2286ab63366STaehee Yoo 2296ab63366STaehee Yoo mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 2306ab63366STaehee Yoo devlink_reload_disable(devlink); 231814b9ce6SDmytro Linkin ret = nsim_dev_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 2326ab63366STaehee Yoo devlink_reload_enable(devlink); 2336ab63366STaehee Yoo mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 234794b2c05SJiri Pirko return ret ? ret : count; 235794b2c05SJiri Pirko } 236794b2c05SJiri Pirko 237794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 238794b2c05SJiri Pirko 23940e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 24040e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 241794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 242794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 24340e4fe4cSJiri Pirko NULL, 24440e4fe4cSJiri Pirko }; 24540e4fe4cSJiri Pirko 24640e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 24740e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 24840e4fe4cSJiri Pirko }; 24940e4fe4cSJiri Pirko 25040e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 25140e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 25240e4fe4cSJiri Pirko NULL, 25340e4fe4cSJiri Pirko }; 25440e4fe4cSJiri Pirko 25540e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 25640e4fe4cSJiri Pirko { 25740e4fe4cSJiri Pirko } 25840e4fe4cSJiri Pirko 25940e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 26040e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 26140e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 26240e4fe4cSJiri Pirko }; 26340e4fe4cSJiri Pirko 264e05b2d14SJiri Pirko static struct nsim_bus_dev * 265e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count); 266e05b2d14SJiri Pirko 267f9d9db47SJiri Pirko static ssize_t 268f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 269f9d9db47SJiri Pirko { 270f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 271f9d9db47SJiri Pirko unsigned int port_count; 272f9d9db47SJiri Pirko unsigned int id; 273f9d9db47SJiri Pirko int err; 274f9d9db47SJiri Pirko 275f9d9db47SJiri Pirko err = sscanf(buf, "%u %u", &id, &port_count); 276f9d9db47SJiri Pirko switch (err) { 277f9d9db47SJiri Pirko case 1: 278f9d9db47SJiri Pirko port_count = 1; 279df561f66SGustavo A. R. Silva fallthrough; 280f9d9db47SJiri Pirko case 2: 281f9d9db47SJiri Pirko if (id > INT_MAX) { 282f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 283f9d9db47SJiri Pirko return -EINVAL; 284f9d9db47SJiri Pirko } 285f9d9db47SJiri Pirko break; 286f9d9db47SJiri Pirko default: 287f9d9db47SJiri Pirko pr_err("Format for adding new device is \"id port_count\" (uint uint).\n"); 288f9d9db47SJiri Pirko return -EINVAL; 289f9d9db47SJiri Pirko } 290f9d9db47SJiri Pirko 291f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 292f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 293f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 294f5cd2160STaehee Yoo err = -EBUSY; 295f5cd2160STaehee Yoo goto err; 296f5cd2160STaehee Yoo } 297f5cd2160STaehee Yoo 298f5cd2160STaehee Yoo nsim_bus_dev = nsim_bus_dev_new(id, port_count); 299f5cd2160STaehee Yoo if (IS_ERR(nsim_bus_dev)) { 300f5cd2160STaehee Yoo err = PTR_ERR(nsim_bus_dev); 301f5cd2160STaehee Yoo goto err; 302f5cd2160STaehee Yoo } 303f5cd2160STaehee Yoo 304f5cd2160STaehee Yoo /* Allow using nsim_bus_dev */ 305f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, true); 306f5cd2160STaehee Yoo 307f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 308f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 309f9d9db47SJiri Pirko 310f9d9db47SJiri Pirko return count; 311f5cd2160STaehee Yoo err: 312f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 313f5cd2160STaehee Yoo return err; 314f9d9db47SJiri Pirko } 315f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 316f9d9db47SJiri Pirko 317e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 318e05b2d14SJiri Pirko 319f9d9db47SJiri Pirko static ssize_t 320f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 321f9d9db47SJiri Pirko { 322f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 323f9d9db47SJiri Pirko unsigned int id; 324f9d9db47SJiri Pirko int err; 325f9d9db47SJiri Pirko 326f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 327f9d9db47SJiri Pirko switch (err) { 328f9d9db47SJiri Pirko case 1: 329f9d9db47SJiri Pirko if (id > INT_MAX) { 330f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 331f9d9db47SJiri Pirko return -EINVAL; 332f9d9db47SJiri Pirko } 333f9d9db47SJiri Pirko break; 334f9d9db47SJiri Pirko default: 335f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 336f9d9db47SJiri Pirko return -EINVAL; 337f9d9db47SJiri Pirko } 338f9d9db47SJiri Pirko 339f9d9db47SJiri Pirko err = -ENOENT; 340f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 341f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 342f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 343f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 344f5cd2160STaehee Yoo return -EBUSY; 345f5cd2160STaehee Yoo } 346f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 347f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 348f9d9db47SJiri Pirko continue; 349f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 350f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 351f9d9db47SJiri Pirko err = 0; 352f9d9db47SJiri Pirko break; 353f9d9db47SJiri Pirko } 354f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 355f9d9db47SJiri Pirko return !err ? count : err; 356f9d9db47SJiri Pirko } 357f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 358f9d9db47SJiri Pirko 359f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 360f9d9db47SJiri Pirko &bus_attr_new_device.attr, 361f9d9db47SJiri Pirko &bus_attr_del_device.attr, 362f9d9db47SJiri Pirko NULL 363f9d9db47SJiri Pirko }; 364f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 365f9d9db47SJiri Pirko 3668320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 3678320d145SJiri Pirko { 3688320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3698320d145SJiri Pirko 3708320d145SJiri Pirko return nsim_dev_probe(nsim_bus_dev); 3718320d145SJiri Pirko } 3728320d145SJiri Pirko 373*fc7a6209SUwe Kleine-König static void nsim_bus_remove(struct device *dev) 3748320d145SJiri Pirko { 3758320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3768320d145SJiri Pirko 3778320d145SJiri Pirko nsim_dev_remove(nsim_bus_dev); 3788320d145SJiri Pirko } 3798320d145SJiri Pirko 38069bbbdc5SYueHaibing static int nsim_num_vf(struct device *dev) 38140e4fe4cSJiri Pirko { 38240e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 38340e4fe4cSJiri Pirko 38440e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 38540e4fe4cSJiri Pirko } 38640e4fe4cSJiri Pirko 38740e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 388925f5afeSJiri Pirko .name = DRV_NAME, 389925f5afeSJiri Pirko .dev_name = DRV_NAME, 390f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 3918320d145SJiri Pirko .probe = nsim_bus_probe, 3928320d145SJiri Pirko .remove = nsim_bus_remove, 393925f5afeSJiri Pirko .num_vf = nsim_num_vf, 394925f5afeSJiri Pirko }; 395925f5afeSJiri Pirko 396d3953819SDmytro Linkin #define NSIM_BUS_DEV_MAX_VFS 4 397d3953819SDmytro Linkin 398e05b2d14SJiri Pirko static struct nsim_bus_dev * 399e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count) 40040e4fe4cSJiri Pirko { 40140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 40240e4fe4cSJiri Pirko int err; 40340e4fe4cSJiri Pirko 40440e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 40540e4fe4cSJiri Pirko if (!nsim_bus_dev) 40640e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 40740e4fe4cSJiri Pirko 408e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 40957ce9774SJiri Pirko if (err < 0) 41057ce9774SJiri Pirko goto err_nsim_bus_dev_free; 41157ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 41240e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 41340e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 414f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 4157b60027bSJiri Pirko nsim_bus_dev->initial_net = current->nsproxy->net_ns; 416d3953819SDmytro Linkin nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS; 4176ab63366STaehee Yoo mutex_init(&nsim_bus_dev->nsim_bus_reload_lock); 418d3953819SDmytro Linkin mutex_init(&nsim_bus_dev->vfs_lock); 419f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 420f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 421f9d9db47SJiri Pirko 422d3953819SDmytro Linkin nsim_bus_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 423d3953819SDmytro Linkin sizeof(struct nsim_vf_config), 424d3953819SDmytro Linkin GFP_KERNEL | __GFP_NOWARN); 425d3953819SDmytro Linkin if (!nsim_bus_dev->vfconfigs) { 426d3953819SDmytro Linkin err = -ENOMEM; 427d3953819SDmytro Linkin goto err_nsim_bus_dev_id_free; 428d3953819SDmytro Linkin } 429d3953819SDmytro Linkin 43040e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 43140e4fe4cSJiri Pirko if (err) 432d3953819SDmytro Linkin goto err_nsim_vfs_free; 433d3953819SDmytro Linkin 43440e4fe4cSJiri Pirko return nsim_bus_dev; 43540e4fe4cSJiri Pirko 436d3953819SDmytro Linkin err_nsim_vfs_free: 437d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 43857ce9774SJiri Pirko err_nsim_bus_dev_id_free: 43957ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 44040e4fe4cSJiri Pirko err_nsim_bus_dev_free: 44140e4fe4cSJiri Pirko kfree(nsim_bus_dev); 44240e4fe4cSJiri Pirko return ERR_PTR(err); 44340e4fe4cSJiri Pirko } 44440e4fe4cSJiri Pirko 445e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 44640e4fe4cSJiri Pirko { 447f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 448f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 44940e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 45057ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 451d3953819SDmytro Linkin kfree(nsim_bus_dev->vfconfigs); 45240e4fe4cSJiri Pirko kfree(nsim_bus_dev); 45340e4fe4cSJiri Pirko } 45440e4fe4cSJiri Pirko 45523d415daSJiri Pirko static struct device_driver nsim_driver = { 45623d415daSJiri Pirko .name = DRV_NAME, 45723d415daSJiri Pirko .bus = &nsim_bus, 45823d415daSJiri Pirko .owner = THIS_MODULE, 45923d415daSJiri Pirko }; 46023d415daSJiri Pirko 461925f5afeSJiri Pirko int nsim_bus_init(void) 462925f5afeSJiri Pirko { 46323d415daSJiri Pirko int err; 46423d415daSJiri Pirko 46523d415daSJiri Pirko err = bus_register(&nsim_bus); 46623d415daSJiri Pirko if (err) 46723d415daSJiri Pirko return err; 46823d415daSJiri Pirko err = driver_register(&nsim_driver); 46923d415daSJiri Pirko if (err) 47023d415daSJiri Pirko goto err_bus_unregister; 471f5cd2160STaehee Yoo /* Allow using resources */ 472f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, true); 47323d415daSJiri Pirko return 0; 47423d415daSJiri Pirko 47523d415daSJiri Pirko err_bus_unregister: 47623d415daSJiri Pirko bus_unregister(&nsim_bus); 47723d415daSJiri Pirko return err; 478925f5afeSJiri Pirko } 479925f5afeSJiri Pirko 480925f5afeSJiri Pirko void nsim_bus_exit(void) 481925f5afeSJiri Pirko { 482f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 483f9d9db47SJiri Pirko 484f5cd2160STaehee Yoo /* Disallow using resources */ 485f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, false); 486f5cd2160STaehee Yoo 487f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 488f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 489f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 490f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 491f9d9db47SJiri Pirko } 492f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 493f5cd2160STaehee Yoo 49423d415daSJiri Pirko driver_unregister(&nsim_driver); 495925f5afeSJiri Pirko bus_unregister(&nsim_bus); 496925f5afeSJiri Pirko } 497