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> 9*f9d9db47SJiri Pirko #include <linux/list.h> 10*f9d9db47SJiri 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); 18*f9d9db47SJiri Pirko static LIST_HEAD(nsim_bus_dev_list); 19*f9d9db47SJiri Pirko static DEFINE_MUTEX(nsim_bus_dev_list_lock); 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 int nsim_bus_dev_vfs_enable(struct nsim_bus_dev *nsim_bus_dev, 2740e4fe4cSJiri Pirko unsigned int num_vfs) 2840e4fe4cSJiri Pirko { 2940e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs = kcalloc(num_vfs, 3040e4fe4cSJiri Pirko sizeof(struct nsim_vf_config), 3140e4fe4cSJiri Pirko GFP_KERNEL); 3240e4fe4cSJiri Pirko if (!nsim_bus_dev->vfconfigs) 3340e4fe4cSJiri Pirko return -ENOMEM; 3440e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = num_vfs; 3540e4fe4cSJiri Pirko 3640e4fe4cSJiri Pirko return 0; 3740e4fe4cSJiri Pirko } 3840e4fe4cSJiri Pirko 3940e4fe4cSJiri Pirko static void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev) 4040e4fe4cSJiri Pirko { 4140e4fe4cSJiri Pirko kfree(nsim_bus_dev->vfconfigs); 4240e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs = NULL; 4340e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = 0; 4440e4fe4cSJiri Pirko } 4540e4fe4cSJiri Pirko 4640e4fe4cSJiri Pirko static ssize_t 4740e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 4840e4fe4cSJiri Pirko const char *buf, size_t count) 4940e4fe4cSJiri Pirko { 5040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 5140e4fe4cSJiri Pirko unsigned int num_vfs; 5240e4fe4cSJiri Pirko int ret; 5340e4fe4cSJiri Pirko 5440e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 5540e4fe4cSJiri Pirko if (ret) 5640e4fe4cSJiri Pirko return ret; 5740e4fe4cSJiri Pirko 5840e4fe4cSJiri Pirko rtnl_lock(); 5940e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs == num_vfs) 6040e4fe4cSJiri Pirko goto exit_good; 6140e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs && num_vfs) { 6240e4fe4cSJiri Pirko ret = -EBUSY; 6340e4fe4cSJiri Pirko goto exit_unlock; 6440e4fe4cSJiri Pirko } 6540e4fe4cSJiri Pirko 6640e4fe4cSJiri Pirko if (num_vfs) { 6740e4fe4cSJiri Pirko ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs); 6840e4fe4cSJiri Pirko if (ret) 6940e4fe4cSJiri Pirko goto exit_unlock; 7040e4fe4cSJiri Pirko } else { 7140e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 7240e4fe4cSJiri Pirko } 7340e4fe4cSJiri Pirko exit_good: 7440e4fe4cSJiri Pirko ret = count; 7540e4fe4cSJiri Pirko exit_unlock: 7640e4fe4cSJiri Pirko rtnl_unlock(); 7740e4fe4cSJiri Pirko 7840e4fe4cSJiri Pirko return ret; 7940e4fe4cSJiri Pirko } 8040e4fe4cSJiri Pirko 8140e4fe4cSJiri Pirko static ssize_t 8240e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 8340e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 8440e4fe4cSJiri Pirko { 8540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 8640e4fe4cSJiri Pirko 8740e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 8840e4fe4cSJiri Pirko } 8940e4fe4cSJiri Pirko 9040e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 9140e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 9240e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 9340e4fe4cSJiri Pirko 9440e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 9540e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 9640e4fe4cSJiri Pirko NULL, 9740e4fe4cSJiri Pirko }; 9840e4fe4cSJiri Pirko 9940e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 10040e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 10140e4fe4cSJiri Pirko }; 10240e4fe4cSJiri Pirko 10340e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 10440e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 10540e4fe4cSJiri Pirko NULL, 10640e4fe4cSJiri Pirko }; 10740e4fe4cSJiri Pirko 10840e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 10940e4fe4cSJiri Pirko { 11040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 11140e4fe4cSJiri Pirko 11240e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 11340e4fe4cSJiri Pirko } 11440e4fe4cSJiri Pirko 11540e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 11640e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 11740e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 11840e4fe4cSJiri Pirko }; 11940e4fe4cSJiri Pirko 120*f9d9db47SJiri Pirko static ssize_t 121*f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 122*f9d9db47SJiri Pirko { 123*f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 124*f9d9db47SJiri Pirko unsigned int port_count; 125*f9d9db47SJiri Pirko unsigned int id; 126*f9d9db47SJiri Pirko int err; 127*f9d9db47SJiri Pirko 128*f9d9db47SJiri Pirko err = sscanf(buf, "%u %u", &id, &port_count); 129*f9d9db47SJiri Pirko switch (err) { 130*f9d9db47SJiri Pirko case 1: 131*f9d9db47SJiri Pirko port_count = 1; 132*f9d9db47SJiri Pirko /* pass through */ 133*f9d9db47SJiri Pirko case 2: 134*f9d9db47SJiri Pirko if (id > INT_MAX) { 135*f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 136*f9d9db47SJiri Pirko return -EINVAL; 137*f9d9db47SJiri Pirko } 138*f9d9db47SJiri Pirko break; 139*f9d9db47SJiri Pirko default: 140*f9d9db47SJiri Pirko pr_err("Format for adding new device is \"id port_count\" (uint uint).\n"); 141*f9d9db47SJiri Pirko return -EINVAL; 142*f9d9db47SJiri Pirko } 143*f9d9db47SJiri Pirko nsim_bus_dev = nsim_bus_dev_new(id, port_count); 144*f9d9db47SJiri Pirko if (IS_ERR(nsim_bus_dev)) 145*f9d9db47SJiri Pirko return PTR_ERR(nsim_bus_dev); 146*f9d9db47SJiri Pirko 147*f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 148*f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 149*f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 150*f9d9db47SJiri Pirko 151*f9d9db47SJiri Pirko return count; 152*f9d9db47SJiri Pirko } 153*f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 154*f9d9db47SJiri Pirko 155*f9d9db47SJiri Pirko static ssize_t 156*f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 157*f9d9db47SJiri Pirko { 158*f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 159*f9d9db47SJiri Pirko unsigned int id; 160*f9d9db47SJiri Pirko int err; 161*f9d9db47SJiri Pirko 162*f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 163*f9d9db47SJiri Pirko switch (err) { 164*f9d9db47SJiri Pirko case 1: 165*f9d9db47SJiri Pirko if (id > INT_MAX) { 166*f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 167*f9d9db47SJiri Pirko return -EINVAL; 168*f9d9db47SJiri Pirko } 169*f9d9db47SJiri Pirko break; 170*f9d9db47SJiri Pirko default: 171*f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 172*f9d9db47SJiri Pirko return -EINVAL; 173*f9d9db47SJiri Pirko } 174*f9d9db47SJiri Pirko 175*f9d9db47SJiri Pirko err = -ENOENT; 176*f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 177*f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 178*f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 179*f9d9db47SJiri Pirko continue; 180*f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 181*f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 182*f9d9db47SJiri Pirko err = 0; 183*f9d9db47SJiri Pirko break; 184*f9d9db47SJiri Pirko } 185*f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 186*f9d9db47SJiri Pirko return !err ? count : err; 187*f9d9db47SJiri Pirko } 188*f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 189*f9d9db47SJiri Pirko 190*f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 191*f9d9db47SJiri Pirko &bus_attr_new_device.attr, 192*f9d9db47SJiri Pirko &bus_attr_del_device.attr, 193*f9d9db47SJiri Pirko NULL 194*f9d9db47SJiri Pirko }; 195*f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 196*f9d9db47SJiri Pirko 19740e4fe4cSJiri Pirko int nsim_num_vf(struct device *dev) 19840e4fe4cSJiri Pirko { 19940e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 20040e4fe4cSJiri Pirko 20140e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 20240e4fe4cSJiri Pirko } 20340e4fe4cSJiri Pirko 20440e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 205925f5afeSJiri Pirko .name = DRV_NAME, 206925f5afeSJiri Pirko .dev_name = DRV_NAME, 207*f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 208925f5afeSJiri Pirko .num_vf = nsim_num_vf, 209925f5afeSJiri Pirko }; 210925f5afeSJiri Pirko 211*f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id, unsigned int port_count) 21240e4fe4cSJiri Pirko { 21340e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 21440e4fe4cSJiri Pirko int err; 21540e4fe4cSJiri Pirko 21640e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 21740e4fe4cSJiri Pirko if (!nsim_bus_dev) 21840e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 21940e4fe4cSJiri Pirko 220*f9d9db47SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, 221*f9d9db47SJiri Pirko id == ~0 ? 0 : id, id, GFP_KERNEL); 22257ce9774SJiri Pirko if (err < 0) 22357ce9774SJiri Pirko goto err_nsim_bus_dev_free; 22457ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 22540e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 22640e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 227*f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 228*f9d9db47SJiri Pirko 22940e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 23040e4fe4cSJiri Pirko if (err) 23157ce9774SJiri Pirko goto err_nsim_bus_dev_id_free; 23240e4fe4cSJiri Pirko return nsim_bus_dev; 23340e4fe4cSJiri Pirko 23457ce9774SJiri Pirko err_nsim_bus_dev_id_free: 23557ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 23640e4fe4cSJiri Pirko err_nsim_bus_dev_free: 23740e4fe4cSJiri Pirko kfree(nsim_bus_dev); 23840e4fe4cSJiri Pirko return ERR_PTR(err); 23940e4fe4cSJiri Pirko } 24040e4fe4cSJiri Pirko 24140e4fe4cSJiri Pirko void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 24240e4fe4cSJiri Pirko { 24340e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 24457ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 24540e4fe4cSJiri Pirko kfree(nsim_bus_dev); 24640e4fe4cSJiri Pirko } 24740e4fe4cSJiri Pirko 24823d415daSJiri Pirko static struct device_driver nsim_driver = { 24923d415daSJiri Pirko .name = DRV_NAME, 25023d415daSJiri Pirko .bus = &nsim_bus, 25123d415daSJiri Pirko .owner = THIS_MODULE, 25223d415daSJiri Pirko }; 25323d415daSJiri Pirko 254925f5afeSJiri Pirko int nsim_bus_init(void) 255925f5afeSJiri Pirko { 25623d415daSJiri Pirko int err; 25723d415daSJiri Pirko 25823d415daSJiri Pirko err = bus_register(&nsim_bus); 25923d415daSJiri Pirko if (err) 26023d415daSJiri Pirko return err; 26123d415daSJiri Pirko err = driver_register(&nsim_driver); 26223d415daSJiri Pirko if (err) 26323d415daSJiri Pirko goto err_bus_unregister; 26423d415daSJiri Pirko return 0; 26523d415daSJiri Pirko 26623d415daSJiri Pirko err_bus_unregister: 26723d415daSJiri Pirko bus_unregister(&nsim_bus); 26823d415daSJiri Pirko return err; 269925f5afeSJiri Pirko } 270925f5afeSJiri Pirko 271925f5afeSJiri Pirko void nsim_bus_exit(void) 272925f5afeSJiri Pirko { 273*f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 274*f9d9db47SJiri Pirko 275*f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 276*f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 277*f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 278*f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 279*f9d9db47SJiri Pirko } 280*f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 28123d415daSJiri Pirko driver_unregister(&nsim_driver); 282925f5afeSJiri Pirko bus_unregister(&nsim_bus); 283925f5afeSJiri Pirko } 284