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> 740e4fe4cSJiri Pirko #include <linux/kernel.h> 840e4fe4cSJiri Pirko #include <linux/rtnetlink.h> 940e4fe4cSJiri Pirko #include <linux/slab.h> 1040e4fe4cSJiri Pirko #include <linux/sysfs.h> 11925f5afeSJiri Pirko 12925f5afeSJiri Pirko #include "netdevsim.h" 13925f5afeSJiri Pirko 1440e4fe4cSJiri Pirko static u32 nsim_bus_dev_id; 1540e4fe4cSJiri Pirko 1640e4fe4cSJiri Pirko static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev) 1740e4fe4cSJiri Pirko { 1840e4fe4cSJiri Pirko return container_of(dev, struct nsim_bus_dev, dev); 1940e4fe4cSJiri Pirko } 2040e4fe4cSJiri Pirko 2140e4fe4cSJiri Pirko static int nsim_bus_dev_vfs_enable(struct nsim_bus_dev *nsim_bus_dev, 2240e4fe4cSJiri Pirko unsigned int num_vfs) 2340e4fe4cSJiri Pirko { 2440e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs = kcalloc(num_vfs, 2540e4fe4cSJiri Pirko sizeof(struct nsim_vf_config), 2640e4fe4cSJiri Pirko GFP_KERNEL); 2740e4fe4cSJiri Pirko if (!nsim_bus_dev->vfconfigs) 2840e4fe4cSJiri Pirko return -ENOMEM; 2940e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = num_vfs; 3040e4fe4cSJiri Pirko 3140e4fe4cSJiri Pirko return 0; 3240e4fe4cSJiri Pirko } 3340e4fe4cSJiri Pirko 3440e4fe4cSJiri Pirko static void nsim_bus_dev_vfs_disable(struct nsim_bus_dev *nsim_bus_dev) 3540e4fe4cSJiri Pirko { 3640e4fe4cSJiri Pirko kfree(nsim_bus_dev->vfconfigs); 3740e4fe4cSJiri Pirko nsim_bus_dev->vfconfigs = NULL; 3840e4fe4cSJiri Pirko nsim_bus_dev->num_vfs = 0; 3940e4fe4cSJiri Pirko } 4040e4fe4cSJiri Pirko 4140e4fe4cSJiri Pirko static ssize_t 4240e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store(struct device *dev, struct device_attribute *attr, 4340e4fe4cSJiri Pirko const char *buf, size_t count) 4440e4fe4cSJiri Pirko { 4540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 4640e4fe4cSJiri Pirko unsigned int num_vfs; 4740e4fe4cSJiri Pirko int ret; 4840e4fe4cSJiri Pirko 4940e4fe4cSJiri Pirko ret = kstrtouint(buf, 0, &num_vfs); 5040e4fe4cSJiri Pirko if (ret) 5140e4fe4cSJiri Pirko return ret; 5240e4fe4cSJiri Pirko 5340e4fe4cSJiri Pirko rtnl_lock(); 5440e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs == num_vfs) 5540e4fe4cSJiri Pirko goto exit_good; 5640e4fe4cSJiri Pirko if (nsim_bus_dev->num_vfs && num_vfs) { 5740e4fe4cSJiri Pirko ret = -EBUSY; 5840e4fe4cSJiri Pirko goto exit_unlock; 5940e4fe4cSJiri Pirko } 6040e4fe4cSJiri Pirko 6140e4fe4cSJiri Pirko if (num_vfs) { 6240e4fe4cSJiri Pirko ret = nsim_bus_dev_vfs_enable(nsim_bus_dev, num_vfs); 6340e4fe4cSJiri Pirko if (ret) 6440e4fe4cSJiri Pirko goto exit_unlock; 6540e4fe4cSJiri Pirko } else { 6640e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 6740e4fe4cSJiri Pirko } 6840e4fe4cSJiri Pirko exit_good: 6940e4fe4cSJiri Pirko ret = count; 7040e4fe4cSJiri Pirko exit_unlock: 7140e4fe4cSJiri Pirko rtnl_unlock(); 7240e4fe4cSJiri Pirko 7340e4fe4cSJiri Pirko return ret; 7440e4fe4cSJiri Pirko } 7540e4fe4cSJiri Pirko 7640e4fe4cSJiri Pirko static ssize_t 7740e4fe4cSJiri Pirko nsim_bus_dev_numvfs_show(struct device *dev, 7840e4fe4cSJiri Pirko struct device_attribute *attr, char *buf) 7940e4fe4cSJiri Pirko { 8040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 8140e4fe4cSJiri Pirko 8240e4fe4cSJiri Pirko return sprintf(buf, "%u\n", nsim_bus_dev->num_vfs); 8340e4fe4cSJiri Pirko } 8440e4fe4cSJiri Pirko 8540e4fe4cSJiri Pirko static struct device_attribute nsim_bus_dev_numvfs_attr = 8640e4fe4cSJiri Pirko __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, 8740e4fe4cSJiri Pirko nsim_bus_dev_numvfs_store); 8840e4fe4cSJiri Pirko 8940e4fe4cSJiri Pirko static struct attribute *nsim_bus_dev_attrs[] = { 9040e4fe4cSJiri Pirko &nsim_bus_dev_numvfs_attr.attr, 9140e4fe4cSJiri Pirko NULL, 9240e4fe4cSJiri Pirko }; 9340e4fe4cSJiri Pirko 9440e4fe4cSJiri Pirko static const struct attribute_group nsim_bus_dev_attr_group = { 9540e4fe4cSJiri Pirko .attrs = nsim_bus_dev_attrs, 9640e4fe4cSJiri Pirko }; 9740e4fe4cSJiri Pirko 9840e4fe4cSJiri Pirko static const struct attribute_group *nsim_bus_dev_attr_groups[] = { 9940e4fe4cSJiri Pirko &nsim_bus_dev_attr_group, 10040e4fe4cSJiri Pirko NULL, 10140e4fe4cSJiri Pirko }; 10240e4fe4cSJiri Pirko 10340e4fe4cSJiri Pirko static void nsim_bus_dev_release(struct device *dev) 10440e4fe4cSJiri Pirko { 10540e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 10640e4fe4cSJiri Pirko 10740e4fe4cSJiri Pirko nsim_bus_dev_vfs_disable(nsim_bus_dev); 10840e4fe4cSJiri Pirko } 10940e4fe4cSJiri Pirko 11040e4fe4cSJiri Pirko static struct device_type nsim_bus_dev_type = { 11140e4fe4cSJiri Pirko .groups = nsim_bus_dev_attr_groups, 11240e4fe4cSJiri Pirko .release = nsim_bus_dev_release, 11340e4fe4cSJiri Pirko }; 11440e4fe4cSJiri Pirko 11540e4fe4cSJiri Pirko int nsim_num_vf(struct device *dev) 11640e4fe4cSJiri Pirko { 11740e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); 11840e4fe4cSJiri Pirko 11940e4fe4cSJiri Pirko return nsim_bus_dev->num_vfs; 12040e4fe4cSJiri Pirko } 12140e4fe4cSJiri Pirko 12240e4fe4cSJiri Pirko static struct bus_type nsim_bus = { 123925f5afeSJiri Pirko .name = DRV_NAME, 124925f5afeSJiri Pirko .dev_name = DRV_NAME, 125925f5afeSJiri Pirko .num_vf = nsim_num_vf, 126925f5afeSJiri Pirko }; 127925f5afeSJiri Pirko 12840e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev_new(void) 12940e4fe4cSJiri Pirko { 13040e4fe4cSJiri Pirko struct nsim_bus_dev *nsim_bus_dev; 13140e4fe4cSJiri Pirko int err; 13240e4fe4cSJiri Pirko 13340e4fe4cSJiri Pirko nsim_bus_dev = kzalloc(sizeof(*nsim_bus_dev), GFP_KERNEL); 13440e4fe4cSJiri Pirko if (!nsim_bus_dev) 13540e4fe4cSJiri Pirko return ERR_PTR(-ENOMEM); 13640e4fe4cSJiri Pirko 13740e4fe4cSJiri Pirko nsim_bus_dev->dev.id = nsim_bus_dev_id++; 13840e4fe4cSJiri Pirko nsim_bus_dev->dev.bus = &nsim_bus; 13940e4fe4cSJiri Pirko nsim_bus_dev->dev.type = &nsim_bus_dev_type; 14040e4fe4cSJiri Pirko err = device_register(&nsim_bus_dev->dev); 14140e4fe4cSJiri Pirko if (err) 14240e4fe4cSJiri Pirko goto err_nsim_bus_dev_free; 14340e4fe4cSJiri Pirko return nsim_bus_dev; 14440e4fe4cSJiri Pirko 14540e4fe4cSJiri Pirko err_nsim_bus_dev_free: 14640e4fe4cSJiri Pirko kfree(nsim_bus_dev); 14740e4fe4cSJiri Pirko return ERR_PTR(err); 14840e4fe4cSJiri Pirko } 14940e4fe4cSJiri Pirko 15040e4fe4cSJiri Pirko void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev) 15140e4fe4cSJiri Pirko { 15240e4fe4cSJiri Pirko device_unregister(&nsim_bus_dev->dev); 15340e4fe4cSJiri Pirko kfree(nsim_bus_dev); 15440e4fe4cSJiri Pirko } 15540e4fe4cSJiri Pirko 156*23d415daSJiri Pirko static struct device_driver nsim_driver = { 157*23d415daSJiri Pirko .name = DRV_NAME, 158*23d415daSJiri Pirko .bus = &nsim_bus, 159*23d415daSJiri Pirko .owner = THIS_MODULE, 160*23d415daSJiri Pirko }; 161*23d415daSJiri Pirko 162925f5afeSJiri Pirko int nsim_bus_init(void) 163925f5afeSJiri Pirko { 164*23d415daSJiri Pirko int err; 165*23d415daSJiri Pirko 166*23d415daSJiri Pirko err = bus_register(&nsim_bus); 167*23d415daSJiri Pirko if (err) 168*23d415daSJiri Pirko return err; 169*23d415daSJiri Pirko err = driver_register(&nsim_driver); 170*23d415daSJiri Pirko if (err) 171*23d415daSJiri Pirko goto err_bus_unregister; 172*23d415daSJiri Pirko return 0; 173*23d415daSJiri Pirko 174*23d415daSJiri Pirko err_bus_unregister: 175*23d415daSJiri Pirko bus_unregister(&nsim_bus); 176*23d415daSJiri Pirko return err; 177925f5afeSJiri Pirko } 178925f5afeSJiri Pirko 179925f5afeSJiri Pirko void nsim_bus_exit(void) 180925f5afeSJiri Pirko { 181*23d415daSJiri Pirko driver_unregister(&nsim_driver); 182925f5afeSJiri Pirko bus_unregister(&nsim_bus); 183925f5afeSJiri Pirko } 184