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/slab.h> 1240e4fe4cSJiri Pirko #include <linux/sysfs.h> 13925f5afeSJiri Pirko 14925f5afeSJiri Pirko #include "netdevsim.h" 15925f5afeSJiri Pirko 1657ce9774SJiri Pirko static DEFINE_IDA(nsim_bus_dev_ids); 17f9d9db47SJiri Pirko static LIST_HEAD(nsim_bus_dev_list); 18f9d9db47SJiri Pirko static DEFINE_MUTEX(nsim_bus_dev_list_lock); 19f5cd2160STaehee Yoo static bool nsim_bus_enable; 2040e4fe4cSJiri Pirko 2140e4fe4cSJiri Pirko static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev) 2240e4fe4cSJiri Pirko { 2340e4fe4cSJiri Pirko return container_of(dev, struct nsim_bus_dev, dev); 2440e4fe4cSJiri Pirko } 2540e4fe4cSJiri Pirko 2640e4fe4cSJiri Pirko static ssize_t 2740e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 2840e4fe4cSJiri Pirko const char *buf, size_t count) 2940e4fe4cSJiri Pirko { 3040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 3140e4fe4cSJiri Pirko unsigned int num_vfs; 3240e4fe4cSJiri Pirko int ret; 3340e4fe4cSJiri Pirko 3440e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 3540e4fe4cSJiri Pirko if (ret) 3640e4fe4cSJiri Pirko return ret; 3740e4fe4cSJiri Pirko 385e388f3dSJakub Kicinski device_lock(dev); 395e388f3dSJakub Kicinski ret = -ENOENT; 401c401078SJakub Kicinski if (dev_get_drvdata(dev)) 411c401078SJakub Kicinski ret = nsim_drv_configure_vfs(nsim_bus_dev, num_vfs); 425e388f3dSJakub Kicinski device_unlock(dev); 4340e4fe4cSJiri Pirko 441c401078SJakub Kicinski return ret ? ret : count; 4540e4fe4cSJiri Pirko } 4640e4fe4cSJiri Pirko 4740e4fe4cSJiri Pirko static ssize_t 4840e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 4940e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 5040e4fe4cSJiri Pirko { 5140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 5240e4fe4cSJiri Pirko 5340e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 5440e4fe4cSJiri Pirko } 5540e4fe4cSJiri Pirko 5640e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 5740e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 5840e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 5940e4fe4cSJiri Pirko 60794b2c05SJiri Pirko static ssize_t 61794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 62794b2c05SJiri Pirko const char *buf, size_t count) 63794b2c05SJiri Pirko { 64794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 65794b2c05SJiri Pirko unsigned int port_index; 66794b2c05SJiri Pirko int ret; 67794b2c05SJiri Pirko 68f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 69f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 70f5cd2160STaehee Yoo return -EBUSY; 71794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 72794b2c05SJiri Pirko if (ret) 73794b2c05SJiri Pirko return ret; 746ab63366STaehee Yoo 75a66f64b8SJakub Kicinski ret = nsim_drv_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 76794b2c05SJiri Pirko return ret ? ret : count; 77794b2c05SJiri Pirko } 78794b2c05SJiri Pirko 79794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 80794b2c05SJiri Pirko 81794b2c05SJiri Pirko static ssize_t 82794b2c05SJiri Pirko del_port_store(struct device *dev, struct device_attribute *attr, 83794b2c05SJiri Pirko const char *buf, size_t count) 84794b2c05SJiri Pirko { 85794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 86794b2c05SJiri Pirko unsigned int port_index; 87794b2c05SJiri Pirko int ret; 88794b2c05SJiri Pirko 89f5cd2160STaehee Yoo /* Prevent to use nsim_bus_dev before initialization. */ 90f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_dev->init)) 91f5cd2160STaehee Yoo return -EBUSY; 92794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 93794b2c05SJiri Pirko if (ret) 94794b2c05SJiri Pirko return ret; 956ab63366STaehee Yoo 96a66f64b8SJakub Kicinski ret = nsim_drv_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_PF, port_index); 97794b2c05SJiri Pirko return ret ? ret : count; 98794b2c05SJiri Pirko } 99794b2c05SJiri Pirko 100794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 101794b2c05SJiri Pirko 10240e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 10340e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 104794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 105794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 10640e4fe4cSJiri Pirko NULL, 10740e4fe4cSJiri Pirko }; 10840e4fe4cSJiri Pirko 10940e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 11040e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 11140e4fe4cSJiri Pirko }; 11240e4fe4cSJiri Pirko 11340e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 11440e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 11540e4fe4cSJiri Pirko NULL, 11640e4fe4cSJiri Pirko }; 11740e4fe4cSJiri Pirko 11840e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 11940e4fe4cSJiri Pirko { 120*cf2010aaSZhengchao Shao struct nsim_bus_dev *nsim_bus_dev; 121*cf2010aaSZhengchao Shao 122*cf2010aaSZhengchao Shao nsim_bus_dev = container_of(dev, struct nsim_bus_dev, dev); 123*cf2010aaSZhengchao Shao kfree(nsim_bus_dev); 12440e4fe4cSJiri Pirko } 12540e4fe4cSJiri Pirko 12640e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 12740e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 12840e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 12940e4fe4cSJiri Pirko }; 13040e4fe4cSJiri Pirko 131e05b2d14SJiri Pirko static struct nsim_bus_dev * 132d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues); 133e05b2d14SJiri Pirko 134f9d9db47SJiri Pirko static ssize_t 135f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 136f9d9db47SJiri Pirko { 137d4861fc6SPeilin Ye unsigned int id, port_count, num_queues; 138f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 139f9d9db47SJiri Pirko int err; 140f9d9db47SJiri Pirko 141d4861fc6SPeilin Ye err = sscanf(buf, "%u %u %u", &id, &port_count, &num_queues); 142f9d9db47SJiri Pirko switch (err) { 143f9d9db47SJiri Pirko case 1: 144f9d9db47SJiri Pirko port_count = 1; 145df561f66SGustavo A. R. Silva fallthrough; 146f9d9db47SJiri Pirko case 2: 147d4861fc6SPeilin Ye num_queues = 1; 148d4861fc6SPeilin Ye fallthrough; 149d4861fc6SPeilin Ye case 3: 150f9d9db47SJiri Pirko if (id > INT_MAX) { 151f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 152f9d9db47SJiri Pirko return -EINVAL; 153f9d9db47SJiri Pirko } 154f9d9db47SJiri Pirko break; 155f9d9db47SJiri Pirko default: 156d4861fc6SPeilin Ye pr_err("Format for adding new device is \"id port_count num_queues\" (uint uint unit).\n"); 157f9d9db47SJiri Pirko return -EINVAL; 158f9d9db47SJiri Pirko } 159f9d9db47SJiri Pirko 160f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 161f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 162f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 163f5cd2160STaehee Yoo err = -EBUSY; 164f5cd2160STaehee Yoo goto err; 165f5cd2160STaehee Yoo } 166f5cd2160STaehee Yoo 167d4861fc6SPeilin Ye nsim_bus_dev = nsim_bus_dev_new(id, port_count, num_queues); 168f5cd2160STaehee Yoo if (IS_ERR(nsim_bus_dev)) { 169f5cd2160STaehee Yoo err = PTR_ERR(nsim_bus_dev); 170f5cd2160STaehee Yoo goto err; 171f5cd2160STaehee Yoo } 172f5cd2160STaehee Yoo 173f5cd2160STaehee Yoo /* Allow using nsim_bus_dev */ 174f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, true); 175f5cd2160STaehee Yoo 176f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 177f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 178f9d9db47SJiri Pirko 179f9d9db47SJiri Pirko return count; 180f5cd2160STaehee Yoo err: 181f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 182f5cd2160STaehee Yoo return err; 183f9d9db47SJiri Pirko } 184f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 185f9d9db47SJiri Pirko 186e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 187e05b2d14SJiri Pirko 188f9d9db47SJiri Pirko static ssize_t 189f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 190f9d9db47SJiri Pirko { 191f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 192f9d9db47SJiri Pirko unsigned int id; 193f9d9db47SJiri Pirko int err; 194f9d9db47SJiri Pirko 195f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 196f9d9db47SJiri Pirko switch (err) { 197f9d9db47SJiri Pirko case 1: 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 deleting device is \"id\" (uint).\n"); 205f9d9db47SJiri Pirko return -EINVAL; 206f9d9db47SJiri Pirko } 207f9d9db47SJiri Pirko 208f9d9db47SJiri Pirko err = -ENOENT; 209f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 210f5cd2160STaehee Yoo /* Prevent to use resource before initialization. */ 211f5cd2160STaehee Yoo if (!smp_load_acquire(&nsim_bus_enable)) { 212f5cd2160STaehee Yoo mutex_unlock(&nsim_bus_dev_list_lock); 213f5cd2160STaehee Yoo return -EBUSY; 214f5cd2160STaehee Yoo } 215f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 216f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 217f9d9db47SJiri Pirko continue; 218f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 219f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 220f9d9db47SJiri Pirko err = 0; 221f9d9db47SJiri Pirko break; 222f9d9db47SJiri Pirko } 223f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 224f9d9db47SJiri Pirko return !err ? count : err; 225f9d9db47SJiri Pirko } 226f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 227f9d9db47SJiri Pirko 228f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 229f9d9db47SJiri Pirko &bus_attr_new_device.attr, 230f9d9db47SJiri Pirko &bus_attr_del_device.attr, 231f9d9db47SJiri Pirko NULL 232f9d9db47SJiri Pirko }; 233f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 234f9d9db47SJiri Pirko 2358320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 2368320d145SJiri Pirko { 2378320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2388320d145SJiri Pirko 239a66f64b8SJakub Kicinski return nsim_drv_probe(nsim_bus_dev); 2408320d145SJiri Pirko } 2418320d145SJiri Pirko 242fc7a6209SUwe Kleine-König static void nsim_bus_remove(struct device *dev) 2438320d145SJiri Pirko { 2448320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2458320d145SJiri Pirko 246a66f64b8SJakub Kicinski nsim_drv_remove(nsim_bus_dev); 2478320d145SJiri Pirko } 2488320d145SJiri Pirko 24969bbbdc5SYueHaibing static int nsim_num_vf(struct device *dev) 25040e4fe4cSJiri Pirko { 25140e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 25240e4fe4cSJiri Pirko 25340e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 25440e4fe4cSJiri Pirko } 25540e4fe4cSJiri Pirko 25640e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 257925f5afeSJiri Pirko .name = DRV_NAME, 258925f5afeSJiri Pirko .dev_name = DRV_NAME, 259f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 2608320d145SJiri Pirko .probe = nsim_bus_probe, 2618320d145SJiri Pirko .remove = nsim_bus_remove, 262925f5afeSJiri Pirko .num_vf = nsim_num_vf, 263925f5afeSJiri Pirko }; 264925f5afeSJiri Pirko 265d3953819SDmytro Linkin #define NSIM_BUS_DEV_MAX_VFS 4 266d3953819SDmytro Linkin 267e05b2d14SJiri Pirko static struct nsim_bus_dev * 268d4861fc6SPeilin Ye nsim_bus_dev_new(unsigned int id, unsigned int port_count, unsigned int num_queues) 26940e4fe4cSJiri Pirko { 27040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 27140e4fe4cSJiri Pirko int err; 27240e4fe4cSJiri Pirko 27340e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 27440e4fe4cSJiri Pirko if (!nsim_bus_dev) 27540e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 27640e4fe4cSJiri Pirko 277e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 27857ce9774SJiri Pirko if (err < 0) 27957ce9774SJiri Pirko goto err_nsim_bus_dev_free; 28057ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 28140e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 28240e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 283f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 284d4861fc6SPeilin Ye nsim_bus_dev->num_queues = num_queues; 2857b60027bSJiri Pirko nsim_bus_dev->initial_net = current->nsproxy->net_ns; 286d3953819SDmytro Linkin nsim_bus_dev->max_vfs = NSIM_BUS_DEV_MAX_VFS; 287f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 288f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 289f9d9db47SJiri Pirko 29040e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 29140e4fe4cSJiri Pirko if (err) 2925e388f3dSJakub Kicinski goto err_nsim_bus_dev_id_free; 293d3953819SDmytro Linkin 29440e4fe4cSJiri Pirko return nsim_bus_dev; 29540e4fe4cSJiri Pirko 29657ce9774SJiri Pirko err_nsim_bus_dev_id_free: 29757ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 298*cf2010aaSZhengchao Shao put_device(&nsim_bus_dev->dev); 299*cf2010aaSZhengchao Shao nsim_bus_dev = NULL; 30040e4fe4cSJiri Pirko err_nsim_bus_dev_free: 30140e4fe4cSJiri Pirko kfree(nsim_bus_dev); 30240e4fe4cSJiri Pirko return ERR_PTR(err); 30340e4fe4cSJiri Pirko } 30440e4fe4cSJiri Pirko 305e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 30640e4fe4cSJiri Pirko { 307f5cd2160STaehee Yoo /* Disallow using nsim_bus_dev */ 308f5cd2160STaehee Yoo smp_store_release(&nsim_bus_dev->init, false); 30957ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 310*cf2010aaSZhengchao Shao device_unregister(&nsim_bus_dev->dev); 31140e4fe4cSJiri Pirko } 31240e4fe4cSJiri Pirko 31323d415daSJiri Pirko static struct device_driver nsim_driver = { 31423d415daSJiri Pirko .name = DRV_NAME, 31523d415daSJiri Pirko .bus = &nsim_bus, 31623d415daSJiri Pirko .owner = THIS_MODULE, 31723d415daSJiri Pirko }; 31823d415daSJiri Pirko 319925f5afeSJiri Pirko int nsim_bus_init(void) 320925f5afeSJiri Pirko { 32123d415daSJiri Pirko int err; 32223d415daSJiri Pirko 32323d415daSJiri Pirko err = bus_register(&nsim_bus); 32423d415daSJiri Pirko if (err) 32523d415daSJiri Pirko return err; 32623d415daSJiri Pirko err = driver_register(&nsim_driver); 32723d415daSJiri Pirko if (err) 32823d415daSJiri Pirko goto err_bus_unregister; 329f5cd2160STaehee Yoo /* Allow using resources */ 330f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, true); 33123d415daSJiri Pirko return 0; 33223d415daSJiri Pirko 33323d415daSJiri Pirko err_bus_unregister: 33423d415daSJiri Pirko bus_unregister(&nsim_bus); 33523d415daSJiri Pirko return err; 336925f5afeSJiri Pirko } 337925f5afeSJiri Pirko 338925f5afeSJiri Pirko void nsim_bus_exit(void) 339925f5afeSJiri Pirko { 340f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 341f9d9db47SJiri Pirko 342f5cd2160STaehee Yoo /* Disallow using resources */ 343f5cd2160STaehee Yoo smp_store_release(&nsim_bus_enable, false); 344f5cd2160STaehee Yoo 345f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 346f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 347f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 348f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 349f9d9db47SJiri Pirko } 350f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 351f5cd2160STaehee Yoo 35223d415daSJiri Pirko driver_unregister(&nsim_driver); 353925f5afeSJiri Pirko bus_unregister(&nsim_bus); 354925f5afeSJiri Pirko } 355