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); 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 94794b2c05SJiri Pirko static ssize_t 95794b2c05SJiri Pirko new_port_store(struct device *dev, struct device_attribute *attr, 96794b2c05SJiri Pirko const char *buf, size_t count) 97794b2c05SJiri Pirko { 98794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 99794b2c05SJiri Pirko unsigned int port_index; 100794b2c05SJiri Pirko int ret; 101794b2c05SJiri Pirko 102794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 103794b2c05SJiri Pirko if (ret) 104794b2c05SJiri Pirko return ret; 105794b2c05SJiri Pirko ret = nsim_dev_port_add(nsim_bus_dev, port_index); 106794b2c05SJiri Pirko return ret ? ret : count; 107794b2c05SJiri Pirko } 108794b2c05SJiri Pirko 109794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); 110794b2c05SJiri Pirko 111794b2c05SJiri Pirko static ssize_t 112794b2c05SJiri Pirko del_port_store(struct device *dev, struct device_attribute *attr, 113794b2c05SJiri Pirko const char *buf, size_t count) 114794b2c05SJiri Pirko { 115794b2c05SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 116794b2c05SJiri Pirko unsigned int port_index; 117794b2c05SJiri Pirko int ret; 118794b2c05SJiri Pirko 119794b2c05SJiri Pirko ret = kstrtouint(buf, 0, &port_index); 120794b2c05SJiri Pirko if (ret) 121794b2c05SJiri Pirko return ret; 122794b2c05SJiri Pirko ret = nsim_dev_port_del(nsim_bus_dev, port_index); 123794b2c05SJiri Pirko return ret ? ret : count; 124794b2c05SJiri Pirko } 125794b2c05SJiri Pirko 126794b2c05SJiri Pirko static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); 127794b2c05SJiri Pirko 12840e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 12940e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 130794b2c05SJiri Pirko &nsim_bus_dev_new_port_attr.attr, 131794b2c05SJiri Pirko &nsim_bus_dev_del_port_attr.attr, 13240e4fe4cSJiri Pirko NULL, 13340e4fe4cSJiri Pirko }; 13440e4fe4cSJiri Pirko 13540e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 13640e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 13740e4fe4cSJiri Pirko }; 13840e4fe4cSJiri Pirko 13940e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 14040e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 14140e4fe4cSJiri Pirko NULL, 14240e4fe4cSJiri Pirko }; 14340e4fe4cSJiri Pirko 14440e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 14540e4fe4cSJiri Pirko { 14640e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 14740e4fe4cSJiri Pirko 14840e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 14940e4fe4cSJiri Pirko } 15040e4fe4cSJiri Pirko 15140e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 15240e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 15340e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 15440e4fe4cSJiri Pirko }; 15540e4fe4cSJiri Pirko 156*e05b2d14SJiri Pirko static struct nsim_bus_dev * 157*e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count); 158*e05b2d14SJiri Pirko 159f9d9db47SJiri Pirko static ssize_t 160f9d9db47SJiri Pirko new_device_store(struct bus_type *bus, const char *buf, size_t count) 161f9d9db47SJiri Pirko { 162f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 163f9d9db47SJiri Pirko unsigned int port_count; 164f9d9db47SJiri Pirko unsigned int id; 165f9d9db47SJiri Pirko int err; 166f9d9db47SJiri Pirko 167f9d9db47SJiri Pirko err = sscanf(buf, "%u %u", &id, &port_count); 168f9d9db47SJiri Pirko switch (err) { 169f9d9db47SJiri Pirko case 1: 170f9d9db47SJiri Pirko port_count = 1; 171f9d9db47SJiri Pirko /* pass through */ 172f9d9db47SJiri Pirko case 2: 173f9d9db47SJiri Pirko if (id > INT_MAX) { 174f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 175f9d9db47SJiri Pirko return -EINVAL; 176f9d9db47SJiri Pirko } 177f9d9db47SJiri Pirko break; 178f9d9db47SJiri Pirko default: 179f9d9db47SJiri Pirko pr_err("Format for adding new device is \"id port_count\" (uint uint).\n"); 180f9d9db47SJiri Pirko return -EINVAL; 181f9d9db47SJiri Pirko } 182f9d9db47SJiri Pirko nsim_bus_dev = nsim_bus_dev_new(id, port_count); 183f9d9db47SJiri Pirko if (IS_ERR(nsim_bus_dev)) 184f9d9db47SJiri Pirko return PTR_ERR(nsim_bus_dev); 185f9d9db47SJiri Pirko 186f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 187f9d9db47SJiri Pirko list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list); 188f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 189f9d9db47SJiri Pirko 190f9d9db47SJiri Pirko return count; 191f9d9db47SJiri Pirko } 192f9d9db47SJiri Pirko static BUS_ATTR_WO(new_device); 193f9d9db47SJiri Pirko 194*e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev); 195*e05b2d14SJiri Pirko 196f9d9db47SJiri Pirko static ssize_t 197f9d9db47SJiri Pirko del_device_store(struct bus_type *bus, const char *buf, size_t count) 198f9d9db47SJiri Pirko { 199f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 200f9d9db47SJiri Pirko unsigned int id; 201f9d9db47SJiri Pirko int err; 202f9d9db47SJiri Pirko 203f9d9db47SJiri Pirko err = sscanf(buf, "%u", &id); 204f9d9db47SJiri Pirko switch (err) { 205f9d9db47SJiri Pirko case 1: 206f9d9db47SJiri Pirko if (id > INT_MAX) { 207f9d9db47SJiri Pirko pr_err("Value of \"id\" is too big.\n"); 208f9d9db47SJiri Pirko return -EINVAL; 209f9d9db47SJiri Pirko } 210f9d9db47SJiri Pirko break; 211f9d9db47SJiri Pirko default: 212f9d9db47SJiri Pirko pr_err("Format for deleting device is \"id\" (uint).\n"); 213f9d9db47SJiri Pirko return -EINVAL; 214f9d9db47SJiri Pirko } 215f9d9db47SJiri Pirko 216f9d9db47SJiri Pirko err = -ENOENT; 217f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 218f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 219f9d9db47SJiri Pirko if (nsim_bus_dev->dev.id != id) 220f9d9db47SJiri Pirko continue; 221f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 222f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 223f9d9db47SJiri Pirko err = 0; 224f9d9db47SJiri Pirko break; 225f9d9db47SJiri Pirko } 226f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 227f9d9db47SJiri Pirko return !err ? count : err; 228f9d9db47SJiri Pirko } 229f9d9db47SJiri Pirko static BUS_ATTR_WO(del_device); 230f9d9db47SJiri Pirko 231f9d9db47SJiri Pirko static struct attribute *nsim_bus_attrs[] = { 232f9d9db47SJiri Pirko &bus_attr_new_device.attr, 233f9d9db47SJiri Pirko &bus_attr_del_device.attr, 234f9d9db47SJiri Pirko NULL 235f9d9db47SJiri Pirko }; 236f9d9db47SJiri Pirko ATTRIBUTE_GROUPS(nsim_bus); 237f9d9db47SJiri Pirko 2388320d145SJiri Pirko static int nsim_bus_probe(struct device *dev) 2398320d145SJiri Pirko { 2408320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2418320d145SJiri Pirko 2428320d145SJiri Pirko return nsim_dev_probe(nsim_bus_dev); 2438320d145SJiri Pirko } 2448320d145SJiri Pirko 2458320d145SJiri Pirko static int nsim_bus_remove(struct device *dev) 2468320d145SJiri Pirko { 2478320d145SJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 2488320d145SJiri Pirko 2498320d145SJiri Pirko nsim_dev_remove(nsim_bus_dev); 2508320d145SJiri Pirko return 0; 2518320d145SJiri Pirko } 2528320d145SJiri Pirko 25340e4fe4cSJiri Pirko int nsim_num_vf(struct device *dev) 25440e4fe4cSJiri Pirko { 25540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 25640e4fe4cSJiri Pirko 25740e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 25840e4fe4cSJiri Pirko } 25940e4fe4cSJiri Pirko 26040e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 261925f5afeSJiri Pirko .name = DRV_NAME, 262925f5afeSJiri Pirko .dev_name = DRV_NAME, 263f9d9db47SJiri Pirko .bus_groups = nsim_bus_groups, 2648320d145SJiri Pirko .probe = nsim_bus_probe, 2658320d145SJiri Pirko .remove = nsim_bus_remove, 266925f5afeSJiri Pirko .num_vf = nsim_num_vf, 267925f5afeSJiri Pirko }; 268925f5afeSJiri Pirko 269*e05b2d14SJiri Pirko static struct nsim_bus_dev * 270*e05b2d14SJiri Pirko nsim_bus_dev_new(unsigned int id, unsigned int port_count) 27140e4fe4cSJiri Pirko { 27240e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 27340e4fe4cSJiri Pirko int err; 27440e4fe4cSJiri Pirko 27540e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 27640e4fe4cSJiri Pirko if (!nsim_bus_dev) 27740e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 27840e4fe4cSJiri Pirko 279*e05b2d14SJiri Pirko err = ida_alloc_range(&nsim_bus_dev_ids, id, id, GFP_KERNEL); 28057ce9774SJiri Pirko if (err < 0) 28157ce9774SJiri Pirko goto err_nsim_bus_dev_free; 28257ce9774SJiri Pirko nsim_bus_dev->dev.id = err; 28340e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 28440e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 285f9d9db47SJiri Pirko nsim_bus_dev->port_count = port_count; 286f9d9db47SJiri Pirko 28740e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 28840e4fe4cSJiri Pirko if (err) 28957ce9774SJiri Pirko goto err_nsim_bus_dev_id_free; 29040e4fe4cSJiri Pirko return nsim_bus_dev; 29140e4fe4cSJiri Pirko 29257ce9774SJiri Pirko err_nsim_bus_dev_id_free: 29357ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 29440e4fe4cSJiri Pirko err_nsim_bus_dev_free: 29540e4fe4cSJiri Pirko kfree(nsim_bus_dev); 29640e4fe4cSJiri Pirko return ERR_PTR(err); 29740e4fe4cSJiri Pirko } 29840e4fe4cSJiri Pirko 299*e05b2d14SJiri Pirko static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 30040e4fe4cSJiri Pirko { 30140e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 30257ce9774SJiri Pirko ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id); 30340e4fe4cSJiri Pirko kfree(nsim_bus_dev); 30440e4fe4cSJiri Pirko } 30540e4fe4cSJiri Pirko 30623d415daSJiri Pirko static struct device_driver nsim_driver = { 30723d415daSJiri Pirko .name = DRV_NAME, 30823d415daSJiri Pirko .bus = &nsim_bus, 30923d415daSJiri Pirko .owner = THIS_MODULE, 31023d415daSJiri Pirko }; 31123d415daSJiri Pirko 312925f5afeSJiri Pirko int nsim_bus_init(void) 313925f5afeSJiri Pirko { 31423d415daSJiri Pirko int err; 31523d415daSJiri Pirko 31623d415daSJiri Pirko err = bus_register(&nsim_bus); 31723d415daSJiri Pirko if (err) 31823d415daSJiri Pirko return err; 31923d415daSJiri Pirko err = driver_register(&nsim_driver); 32023d415daSJiri Pirko if (err) 32123d415daSJiri Pirko goto err_bus_unregister; 32223d415daSJiri Pirko return 0; 32323d415daSJiri Pirko 32423d415daSJiri Pirko err_bus_unregister: 32523d415daSJiri Pirko bus_unregister(&nsim_bus); 32623d415daSJiri Pirko return err; 327925f5afeSJiri Pirko } 328925f5afeSJiri Pirko 329925f5afeSJiri Pirko void nsim_bus_exit(void) 330925f5afeSJiri Pirko { 331f9d9db47SJiri Pirko struct nsim_bus_dev *nsim_bus_dev, *tmp; 332f9d9db47SJiri Pirko 333f9d9db47SJiri Pirko mutex_lock(&nsim_bus_dev_list_lock); 334f9d9db47SJiri Pirko list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) { 335f9d9db47SJiri Pirko list_del(&nsim_bus_dev->list); 336f9d9db47SJiri Pirko nsim_bus_dev_del(nsim_bus_dev); 337f9d9db47SJiri Pirko } 338f9d9db47SJiri Pirko mutex_unlock(&nsim_bus_dev_list_lock); 33923d415daSJiri Pirko driver_unregister(&nsim_driver); 340925f5afeSJiri Pirko bus_unregister(&nsim_bus); 341925f5afeSJiri Pirko } 342