18fb4bc6fSJiri Pirko /* 28fb4bc6fSJiri Pirko * Copyright (c) 2018 Cumulus Networks. All rights reserved. 38fb4bc6fSJiri Pirko * Copyright (c) 2018 David Ahern <[email protected]> 48fb4bc6fSJiri Pirko * Copyright (c) 2019 Mellanox Technologies. All rights reserved. 58fb4bc6fSJiri Pirko * 68fb4bc6fSJiri Pirko * This software is licensed under the GNU General License Version 2, 78fb4bc6fSJiri Pirko * June 1991 as shown in the file COPYING in the top-level directory of this 88fb4bc6fSJiri Pirko * source tree. 98fb4bc6fSJiri Pirko * 108fb4bc6fSJiri Pirko * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 118fb4bc6fSJiri Pirko * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 128fb4bc6fSJiri Pirko * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 138fb4bc6fSJiri Pirko * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 148fb4bc6fSJiri Pirko * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 158fb4bc6fSJiri Pirko * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 168fb4bc6fSJiri Pirko */ 178fb4bc6fSJiri Pirko 18d514f41eSJiri Pirko #include <linux/debugfs.h> 198fb4bc6fSJiri Pirko #include <linux/device.h> 20da58f90fSIdo Schimmel #include <linux/etherdevice.h> 21da58f90fSIdo Schimmel #include <linux/inet.h> 22da58f90fSIdo Schimmel #include <linux/jiffies.h> 23da58f90fSIdo Schimmel #include <linux/kernel.h> 248320d145SJiri Pirko #include <linux/list.h> 25794b2c05SJiri Pirko #include <linux/mutex.h> 26514cf64cSJiri Pirko #include <linux/random.h> 278fb4bc6fSJiri Pirko #include <linux/rtnetlink.h> 28da58f90fSIdo Schimmel #include <linux/workqueue.h> 298fb4bc6fSJiri Pirko #include <net/devlink.h> 30da58f90fSIdo Schimmel #include <net/ip.h> 31d3cbb907SJiri Pirko #include <net/flow_offload.h> 32da58f90fSIdo Schimmel #include <uapi/linux/devlink.h> 33da58f90fSIdo Schimmel #include <uapi/linux/ip.h> 34da58f90fSIdo Schimmel #include <uapi/linux/udp.h> 358fb4bc6fSJiri Pirko 368fb4bc6fSJiri Pirko #include "netdevsim.h" 378fb4bc6fSJiri Pirko 38814b9ce6SDmytro Linkin static unsigned int 39814b9ce6SDmytro Linkin nsim_dev_port_index(enum nsim_dev_port_type type, unsigned int port_index) 40814b9ce6SDmytro Linkin { 41814b9ce6SDmytro Linkin switch (type) { 42814b9ce6SDmytro Linkin case NSIM_DEV_PORT_TYPE_VF: 43814b9ce6SDmytro Linkin port_index = NSIM_DEV_VF_PORT_INDEX_BASE + port_index; 44814b9ce6SDmytro Linkin break; 45814b9ce6SDmytro Linkin case NSIM_DEV_PORT_TYPE_PF: 46814b9ce6SDmytro Linkin break; 47814b9ce6SDmytro Linkin } 48814b9ce6SDmytro Linkin 49814b9ce6SDmytro Linkin return port_index; 50814b9ce6SDmytro Linkin } 51814b9ce6SDmytro Linkin 52814b9ce6SDmytro Linkin static inline unsigned int nsim_dev_port_index_to_vf_index(unsigned int port_index) 53814b9ce6SDmytro Linkin { 54814b9ce6SDmytro Linkin return port_index - NSIM_DEV_VF_PORT_INDEX_BASE; 55814b9ce6SDmytro Linkin } 56814b9ce6SDmytro Linkin 57d514f41eSJiri Pirko static struct dentry *nsim_dev_ddir; 58d514f41eSJiri Pirko 595e388f3dSJakub Kicinski unsigned int nsim_dev_get_vfs(struct nsim_dev *nsim_dev) 605e388f3dSJakub Kicinski { 615e388f3dSJakub Kicinski WARN_ON(!lockdep_rtnl_is_held() && 62aff3a925SJakub Kicinski !devl_lock_is_held(priv_to_devlink(nsim_dev))); 635e388f3dSJakub Kicinski 645e388f3dSJakub Kicinski return nsim_dev->nsim_bus_dev->num_vfs; 655e388f3dSJakub Kicinski } 665e388f3dSJakub Kicinski 671c401078SJakub Kicinski static void 681c401078SJakub Kicinski nsim_bus_dev_set_vfs(struct nsim_bus_dev *nsim_bus_dev, unsigned int num_vfs) 691c401078SJakub Kicinski { 701c401078SJakub Kicinski rtnl_lock(); 711c401078SJakub Kicinski nsim_bus_dev->num_vfs = num_vfs; 721c401078SJakub Kicinski rtnl_unlock(); 731c401078SJakub Kicinski } 741c401078SJakub Kicinski 754418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SIZE (1024 * 32) 764418f862SJiri Pirko 773fe0fd53SJacob Keller static int 78d4602a9fSAndrew Lunn nsim_dev_take_snapshot(struct devlink *devlink, 79d4602a9fSAndrew Lunn const struct devlink_region_ops *ops, 80d4602a9fSAndrew Lunn struct netlink_ext_ack *extack, 813fe0fd53SJacob Keller u8 **data) 824418f862SJiri Pirko { 834418f862SJiri Pirko void *dummy_data; 8412102436SJacob Keller 854418f862SJiri Pirko dummy_data = kmalloc(NSIM_DEV_DUMMY_REGION_SIZE, GFP_KERNEL); 864418f862SJiri Pirko if (!dummy_data) 874418f862SJiri Pirko return -ENOMEM; 884418f862SJiri Pirko 894418f862SJiri Pirko get_random_bytes(dummy_data, NSIM_DEV_DUMMY_REGION_SIZE); 904418f862SJiri Pirko 913fe0fd53SJacob Keller *data = dummy_data; 923fe0fd53SJacob Keller 933fe0fd53SJacob Keller return 0; 943fe0fd53SJacob Keller } 953fe0fd53SJacob Keller 963fe0fd53SJacob Keller static ssize_t nsim_dev_take_snapshot_write(struct file *file, 973fe0fd53SJacob Keller const char __user *data, 983fe0fd53SJacob Keller size_t count, loff_t *ppos) 993fe0fd53SJacob Keller { 1003fe0fd53SJacob Keller struct nsim_dev *nsim_dev = file->private_data; 1013fe0fd53SJacob Keller struct devlink *devlink; 1023fe0fd53SJacob Keller u8 *dummy_data; 1033fe0fd53SJacob Keller int err; 1043fe0fd53SJacob Keller u32 id; 1053fe0fd53SJacob Keller 1063fe0fd53SJacob Keller devlink = priv_to_devlink(nsim_dev); 1073fe0fd53SJacob Keller 108d4602a9fSAndrew Lunn err = nsim_dev_take_snapshot(devlink, NULL, NULL, &dummy_data); 1093fe0fd53SJacob Keller if (err) 1103fe0fd53SJacob Keller return err; 1113fe0fd53SJacob Keller 11212102436SJacob Keller err = devlink_region_snapshot_id_get(devlink, &id); 1137ef19d3bSJacob Keller if (err) { 1147ef19d3bSJacob Keller pr_err("Failed to get snapshot id\n"); 1153902baf9SGustavo A. R. Silva kfree(dummy_data); 1167ef19d3bSJacob Keller return err; 1177ef19d3bSJacob Keller } 1184418f862SJiri Pirko err = devlink_region_snapshot_create(nsim_dev->dummy_region, 119a0a09f6bSJacob Keller dummy_data, id); 12012102436SJacob Keller devlink_region_snapshot_id_put(devlink, id); 1214418f862SJiri Pirko if (err) { 1224418f862SJiri Pirko pr_err("Failed to create region snapshot\n"); 1234418f862SJiri Pirko kfree(dummy_data); 1244418f862SJiri Pirko return err; 1254418f862SJiri Pirko } 1264418f862SJiri Pirko 1274418f862SJiri Pirko return count; 1284418f862SJiri Pirko } 1294418f862SJiri Pirko 1304418f862SJiri Pirko static const struct file_operations nsim_dev_take_snapshot_fops = { 1314418f862SJiri Pirko .open = simple_open, 1324418f862SJiri Pirko .write = nsim_dev_take_snapshot_write, 1334418f862SJiri Pirko .llseek = generic_file_llseek, 134a5bbcbf2STaehee Yoo .owner = THIS_MODULE, 1354418f862SJiri Pirko }; 1364418f862SJiri Pirko 137d3cbb907SJiri Pirko static ssize_t nsim_dev_trap_fa_cookie_read(struct file *file, 138d3cbb907SJiri Pirko char __user *data, 139d3cbb907SJiri Pirko size_t count, loff_t *ppos) 140d3cbb907SJiri Pirko { 141d3cbb907SJiri Pirko struct nsim_dev *nsim_dev = file->private_data; 142d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie; 143d3cbb907SJiri Pirko unsigned int buf_len; 144d3cbb907SJiri Pirko ssize_t ret; 145d3cbb907SJiri Pirko char *buf; 146d3cbb907SJiri Pirko 147d3cbb907SJiri Pirko spin_lock(&nsim_dev->fa_cookie_lock); 148d3cbb907SJiri Pirko fa_cookie = nsim_dev->fa_cookie; 149d3cbb907SJiri Pirko if (!fa_cookie) { 150d3cbb907SJiri Pirko ret = -EINVAL; 151d3cbb907SJiri Pirko goto errout; 152d3cbb907SJiri Pirko } 153d3cbb907SJiri Pirko buf_len = fa_cookie->cookie_len * 2; 154d3cbb907SJiri Pirko buf = kmalloc(buf_len, GFP_ATOMIC); 155d3cbb907SJiri Pirko if (!buf) { 156d3cbb907SJiri Pirko ret = -ENOMEM; 157d3cbb907SJiri Pirko goto errout; 158d3cbb907SJiri Pirko } 159d3cbb907SJiri Pirko bin2hex(buf, fa_cookie->cookie, fa_cookie->cookie_len); 160d3cbb907SJiri Pirko spin_unlock(&nsim_dev->fa_cookie_lock); 161d3cbb907SJiri Pirko 162d3cbb907SJiri Pirko ret = simple_read_from_buffer(data, count, ppos, buf, buf_len); 163d3cbb907SJiri Pirko 164d3cbb907SJiri Pirko kfree(buf); 165d3cbb907SJiri Pirko return ret; 166d3cbb907SJiri Pirko 167d3cbb907SJiri Pirko errout: 168d3cbb907SJiri Pirko spin_unlock(&nsim_dev->fa_cookie_lock); 169d3cbb907SJiri Pirko return ret; 170d3cbb907SJiri Pirko } 171d3cbb907SJiri Pirko 172d3cbb907SJiri Pirko static ssize_t nsim_dev_trap_fa_cookie_write(struct file *file, 173d3cbb907SJiri Pirko const char __user *data, 174d3cbb907SJiri Pirko size_t count, loff_t *ppos) 175d3cbb907SJiri Pirko { 176d3cbb907SJiri Pirko struct nsim_dev *nsim_dev = file->private_data; 177d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie; 178d3cbb907SJiri Pirko size_t cookie_len; 179d3cbb907SJiri Pirko ssize_t ret; 180d3cbb907SJiri Pirko char *buf; 181d3cbb907SJiri Pirko 182d3cbb907SJiri Pirko if (*ppos != 0) 183d3cbb907SJiri Pirko return -EINVAL; 184d3cbb907SJiri Pirko cookie_len = (count - 1) / 2; 185d3cbb907SJiri Pirko if ((count - 1) % 2) 186d3cbb907SJiri Pirko return -EINVAL; 187d3cbb907SJiri Pirko buf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN); 188d3cbb907SJiri Pirko if (!buf) 189d3cbb907SJiri Pirko return -ENOMEM; 190d3cbb907SJiri Pirko 191d3cbb907SJiri Pirko ret = simple_write_to_buffer(buf, count, ppos, data, count); 192d3cbb907SJiri Pirko if (ret < 0) 193d3cbb907SJiri Pirko goto free_buf; 194d3cbb907SJiri Pirko 195d3cbb907SJiri Pirko fa_cookie = kmalloc(sizeof(*fa_cookie) + cookie_len, 196d3cbb907SJiri Pirko GFP_KERNEL | __GFP_NOWARN); 197d3cbb907SJiri Pirko if (!fa_cookie) { 198d3cbb907SJiri Pirko ret = -ENOMEM; 199d3cbb907SJiri Pirko goto free_buf; 200d3cbb907SJiri Pirko } 201d3cbb907SJiri Pirko 202d3cbb907SJiri Pirko fa_cookie->cookie_len = cookie_len; 203d3cbb907SJiri Pirko ret = hex2bin(fa_cookie->cookie, buf, cookie_len); 204d3cbb907SJiri Pirko if (ret) 205d3cbb907SJiri Pirko goto free_fa_cookie; 206d3cbb907SJiri Pirko kfree(buf); 207d3cbb907SJiri Pirko 208d3cbb907SJiri Pirko spin_lock(&nsim_dev->fa_cookie_lock); 209d3cbb907SJiri Pirko kfree(nsim_dev->fa_cookie); 210d3cbb907SJiri Pirko nsim_dev->fa_cookie = fa_cookie; 211d3cbb907SJiri Pirko spin_unlock(&nsim_dev->fa_cookie_lock); 212d3cbb907SJiri Pirko 213d3cbb907SJiri Pirko return count; 214d3cbb907SJiri Pirko 215d3cbb907SJiri Pirko free_fa_cookie: 216d3cbb907SJiri Pirko kfree(fa_cookie); 217d3cbb907SJiri Pirko free_buf: 218d3cbb907SJiri Pirko kfree(buf); 219d3cbb907SJiri Pirko return ret; 220d3cbb907SJiri Pirko } 221d3cbb907SJiri Pirko 222d3cbb907SJiri Pirko static const struct file_operations nsim_dev_trap_fa_cookie_fops = { 223d3cbb907SJiri Pirko .open = simple_open, 224d3cbb907SJiri Pirko .read = nsim_dev_trap_fa_cookie_read, 225d3cbb907SJiri Pirko .write = nsim_dev_trap_fa_cookie_write, 226d3cbb907SJiri Pirko .llseek = generic_file_llseek, 227a5bbcbf2STaehee Yoo .owner = THIS_MODULE, 228d3cbb907SJiri Pirko }; 229d3cbb907SJiri Pirko 230a3353ec3SJakub Kicinski static ssize_t nsim_bus_dev_max_vfs_read(struct file *file, char __user *data, 231a3353ec3SJakub Kicinski size_t count, loff_t *ppos) 232a3353ec3SJakub Kicinski { 233a3353ec3SJakub Kicinski struct nsim_dev *nsim_dev = file->private_data; 234a3353ec3SJakub Kicinski char buf[11]; 235a3353ec3SJakub Kicinski ssize_t len; 236a3353ec3SJakub Kicinski 237a3353ec3SJakub Kicinski len = scnprintf(buf, sizeof(buf), "%u\n", 238a3353ec3SJakub Kicinski READ_ONCE(nsim_dev->nsim_bus_dev->max_vfs)); 239a3353ec3SJakub Kicinski 240a3353ec3SJakub Kicinski return simple_read_from_buffer(data, count, ppos, buf, len); 241a3353ec3SJakub Kicinski } 242a3353ec3SJakub Kicinski 243a3353ec3SJakub Kicinski static ssize_t nsim_bus_dev_max_vfs_write(struct file *file, 244a3353ec3SJakub Kicinski const char __user *data, 245a3353ec3SJakub Kicinski size_t count, loff_t *ppos) 246a3353ec3SJakub Kicinski { 247a3353ec3SJakub Kicinski struct nsim_vf_config *vfconfigs; 248a3353ec3SJakub Kicinski struct nsim_dev *nsim_dev; 249a3353ec3SJakub Kicinski char buf[10]; 250a3353ec3SJakub Kicinski ssize_t ret; 251a3353ec3SJakub Kicinski u32 val; 252a3353ec3SJakub Kicinski 253a3353ec3SJakub Kicinski if (*ppos != 0) 254a3353ec3SJakub Kicinski return 0; 255a3353ec3SJakub Kicinski 256a3353ec3SJakub Kicinski if (count >= sizeof(buf)) 257a3353ec3SJakub Kicinski return -ENOSPC; 258a3353ec3SJakub Kicinski 259a3353ec3SJakub Kicinski ret = copy_from_user(buf, data, count); 260a3353ec3SJakub Kicinski if (ret) 261a3353ec3SJakub Kicinski return -EFAULT; 262a3353ec3SJakub Kicinski buf[count] = '\0'; 263a3353ec3SJakub Kicinski 264a3353ec3SJakub Kicinski ret = kstrtouint(buf, 10, &val); 265a3353ec3SJakub Kicinski if (ret) 266a3353ec3SJakub Kicinski return -EINVAL; 267a3353ec3SJakub Kicinski 268a3353ec3SJakub Kicinski /* max_vfs limited by the maximum number of provided port indexes */ 269a3353ec3SJakub Kicinski if (val > NSIM_DEV_VF_PORT_INDEX_MAX - NSIM_DEV_VF_PORT_INDEX_BASE) 270a3353ec3SJakub Kicinski return -ERANGE; 271a3353ec3SJakub Kicinski 272a3353ec3SJakub Kicinski vfconfigs = kcalloc(val, sizeof(struct nsim_vf_config), 273a3353ec3SJakub Kicinski GFP_KERNEL | __GFP_NOWARN); 274a3353ec3SJakub Kicinski if (!vfconfigs) 275a3353ec3SJakub Kicinski return -ENOMEM; 276a3353ec3SJakub Kicinski 277a3353ec3SJakub Kicinski nsim_dev = file->private_data; 278aff3a925SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 279a3353ec3SJakub Kicinski /* Reject if VFs are configured */ 280a3353ec3SJakub Kicinski if (nsim_dev_get_vfs(nsim_dev)) { 281a3353ec3SJakub Kicinski ret = -EBUSY; 282a3353ec3SJakub Kicinski } else { 283a3353ec3SJakub Kicinski swap(nsim_dev->vfconfigs, vfconfigs); 284a3353ec3SJakub Kicinski WRITE_ONCE(nsim_dev->nsim_bus_dev->max_vfs, val); 285a3353ec3SJakub Kicinski *ppos += count; 286a3353ec3SJakub Kicinski ret = count; 287a3353ec3SJakub Kicinski } 288aff3a925SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 289a3353ec3SJakub Kicinski 290a3353ec3SJakub Kicinski kfree(vfconfigs); 291a3353ec3SJakub Kicinski return ret; 292a3353ec3SJakub Kicinski } 293a3353ec3SJakub Kicinski 294d3953819SDmytro Linkin static const struct file_operations nsim_dev_max_vfs_fops = { 295d3953819SDmytro Linkin .open = simple_open, 296d3953819SDmytro Linkin .read = nsim_bus_dev_max_vfs_read, 297d3953819SDmytro Linkin .write = nsim_bus_dev_max_vfs_write, 298d3953819SDmytro Linkin .llseek = generic_file_llseek, 299d3953819SDmytro Linkin .owner = THIS_MODULE, 300d3953819SDmytro Linkin }; 301d3953819SDmytro Linkin 302d514f41eSJiri Pirko static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev) 303d514f41eSJiri Pirko { 3046fb8852bSTaehee Yoo char dev_ddir_name[sizeof(DRV_NAME) + 10]; 305f3d101b4SDmytro Linkin int err; 306d514f41eSJiri Pirko 307ab1d0cc0SJiri Pirko sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id); 308d514f41eSJiri Pirko nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir); 3096556ff32STaehee Yoo if (IS_ERR(nsim_dev->ddir)) 3106556ff32STaehee Yoo return PTR_ERR(nsim_dev->ddir); 311ab1d0cc0SJiri Pirko nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir); 3126556ff32STaehee Yoo if (IS_ERR(nsim_dev->ports_ddir)) 3136556ff32STaehee Yoo return PTR_ERR(nsim_dev->ports_ddir); 314fa4dfc4aSJiri Pirko debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir, 315fa4dfc4aSJiri Pirko &nsim_dev->fw_update_status); 316cbb58368SJacob Keller debugfs_create_u32("fw_update_overwrite_mask", 0600, nsim_dev->ddir, 317cbb58368SJacob Keller &nsim_dev->fw_update_overwrite_mask); 318150e8f8aSJiri Pirko debugfs_create_u32("max_macs", 0600, nsim_dev->ddir, 319150e8f8aSJiri Pirko &nsim_dev->max_macs); 320150e8f8aSJiri Pirko debugfs_create_bool("test1", 0600, nsim_dev->ddir, 321150e8f8aSJiri Pirko &nsim_dev->test1); 3228526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 3238526ad96STaehee Yoo 0200, 3248526ad96STaehee Yoo nsim_dev->ddir, 3258526ad96STaehee Yoo nsim_dev, 3264418f862SJiri Pirko &nsim_dev_take_snapshot_fops); 327155ddfc5SJiri Pirko debugfs_create_bool("dont_allow_reload", 0600, nsim_dev->ddir, 328155ddfc5SJiri Pirko &nsim_dev->dont_allow_reload); 329155ddfc5SJiri Pirko debugfs_create_bool("fail_reload", 0600, nsim_dev->ddir, 330155ddfc5SJiri Pirko &nsim_dev->fail_reload); 331d3cbb907SJiri Pirko debugfs_create_file("trap_flow_action_cookie", 0600, nsim_dev->ddir, 332d3cbb907SJiri Pirko nsim_dev, &nsim_dev_trap_fa_cookie_fops); 3330dc8249aSIdo Schimmel debugfs_create_bool("fail_trap_group_set", 0600, 3340dc8249aSIdo Schimmel nsim_dev->ddir, 3350dc8249aSIdo Schimmel &nsim_dev->fail_trap_group_set); 336ad188458SIdo Schimmel debugfs_create_bool("fail_trap_policer_set", 0600, 337ad188458SIdo Schimmel nsim_dev->ddir, 338ad188458SIdo Schimmel &nsim_dev->fail_trap_policer_set); 339ad188458SIdo Schimmel debugfs_create_bool("fail_trap_policer_counter_get", 0600, 340ad188458SIdo Schimmel nsim_dev->ddir, 341ad188458SIdo Schimmel &nsim_dev->fail_trap_policer_counter_get); 342aff3a925SJakub Kicinski /* caution, dev_max_vfs write takes devlink lock */ 343ba064e4cSJakub Kicinski debugfs_create_file("max_vfs", 0600, nsim_dev->ddir, 3445e388f3dSJakub Kicinski nsim_dev, &nsim_dev_max_vfs_fops); 345ba064e4cSJakub Kicinski 346885226f5SDmytro Linkin nsim_dev->nodes_ddir = debugfs_create_dir("rate_nodes", nsim_dev->ddir); 347f3d101b4SDmytro Linkin if (IS_ERR(nsim_dev->nodes_ddir)) { 348f3d101b4SDmytro Linkin err = PTR_ERR(nsim_dev->nodes_ddir); 349f3d101b4SDmytro Linkin goto err_out; 350f3d101b4SDmytro Linkin } 351275b51c2SOleksandr Mazur debugfs_create_bool("fail_trap_drop_counter_get", 0600, 352a7b3527aSOleksandr Mazur nsim_dev->ddir, 353275b51c2SOleksandr Mazur &nsim_dev->fail_trap_drop_counter_get); 354424be63aSJakub Kicinski nsim_udp_tunnels_debugfs_create(nsim_dev); 355d514f41eSJiri Pirko return 0; 356f3d101b4SDmytro Linkin 357f3d101b4SDmytro Linkin err_out: 358f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ports_ddir); 359f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ddir); 360f3d101b4SDmytro Linkin return err; 361d514f41eSJiri Pirko } 362d514f41eSJiri Pirko 363d514f41eSJiri Pirko static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev) 364d514f41eSJiri Pirko { 365885226f5SDmytro Linkin debugfs_remove_recursive(nsim_dev->nodes_ddir); 366ab1d0cc0SJiri Pirko debugfs_remove_recursive(nsim_dev->ports_ddir); 367d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev->ddir); 368d514f41eSJiri Pirko } 369d514f41eSJiri Pirko 370f3d101b4SDmytro Linkin static ssize_t nsim_dev_rate_parent_read(struct file *file, 371f3d101b4SDmytro Linkin char __user *data, 372f3d101b4SDmytro Linkin size_t count, loff_t *ppos) 373f3d101b4SDmytro Linkin { 374f3d101b4SDmytro Linkin char **name_ptr = file->private_data; 375f3d101b4SDmytro Linkin size_t len; 376f3d101b4SDmytro Linkin 377f3d101b4SDmytro Linkin if (!*name_ptr) 378f3d101b4SDmytro Linkin return 0; 379f3d101b4SDmytro Linkin 380f3d101b4SDmytro Linkin len = strlen(*name_ptr); 381f3d101b4SDmytro Linkin return simple_read_from_buffer(data, count, ppos, *name_ptr, len); 382f3d101b4SDmytro Linkin } 383f3d101b4SDmytro Linkin 384f3d101b4SDmytro Linkin static const struct file_operations nsim_dev_rate_parent_fops = { 385f3d101b4SDmytro Linkin .open = simple_open, 386f3d101b4SDmytro Linkin .read = nsim_dev_rate_parent_read, 387f3d101b4SDmytro Linkin .llseek = generic_file_llseek, 388f3d101b4SDmytro Linkin .owner = THIS_MODULE, 389f3d101b4SDmytro Linkin }; 390f3d101b4SDmytro Linkin 3918320d145SJiri Pirko static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev, 3928320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port) 3938320d145SJiri Pirko { 394605c4f8fSDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 395605c4f8fSDmytro Linkin unsigned int port_index = nsim_dev_port->port_index; 3968320d145SJiri Pirko char port_ddir_name[16]; 3978320d145SJiri Pirko char dev_link_name[32]; 3988320d145SJiri Pirko 399605c4f8fSDmytro Linkin sprintf(port_ddir_name, "%u", port_index); 4008320d145SJiri Pirko nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name, 4018320d145SJiri Pirko nsim_dev->ports_ddir); 4026556ff32STaehee Yoo if (IS_ERR(nsim_dev_port->ddir)) 4036556ff32STaehee Yoo return PTR_ERR(nsim_dev_port->ddir); 4048320d145SJiri Pirko 405605c4f8fSDmytro Linkin sprintf(dev_link_name, "../../../" DRV_NAME "%u", nsim_bus_dev->dev.id); 406605c4f8fSDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 407605c4f8fSDmytro Linkin unsigned int vf_id = nsim_dev_port_index_to_vf_index(port_index); 408605c4f8fSDmytro Linkin 409605c4f8fSDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_dev_port->ddir, 4105e388f3dSJakub Kicinski &nsim_dev->vfconfigs[vf_id].min_tx_rate); 411605c4f8fSDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_dev_port->ddir, 4125e388f3dSJakub Kicinski &nsim_dev->vfconfigs[vf_id].max_tx_rate); 413f3d101b4SDmytro Linkin nsim_dev_port->rate_parent = debugfs_create_file("rate_parent", 414f3d101b4SDmytro Linkin 0400, 415f3d101b4SDmytro Linkin nsim_dev_port->ddir, 416f3d101b4SDmytro Linkin &nsim_dev_port->parent_name, 417f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 418605c4f8fSDmytro Linkin } 4198320d145SJiri Pirko debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name); 4208320d145SJiri Pirko 4218320d145SJiri Pirko return 0; 4228320d145SJiri Pirko } 4238320d145SJiri Pirko 4248320d145SJiri Pirko static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port) 4258320d145SJiri Pirko { 4268320d145SJiri Pirko debugfs_remove_recursive(nsim_dev_port->ddir); 4278320d145SJiri Pirko } 4288320d145SJiri Pirko 4298fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink) 4308fb4bc6fSJiri Pirko { 4318fb4bc6fSJiri Pirko struct devlink_resource_size_params params = { 4328fb4bc6fSJiri Pirko .size_max = (u64)-1, 4338fb4bc6fSJiri Pirko .size_granularity = 1, 4348fb4bc6fSJiri Pirko .unit = DEVLINK_RESOURCE_UNIT_ENTRY 4358fb4bc6fSJiri Pirko }; 4368fb4bc6fSJiri Pirko int err; 4378fb4bc6fSJiri Pirko 4388fb4bc6fSJiri Pirko /* Resources for IPv4 */ 439012ec02aSJiri Pirko err = devl_resource_register(devlink, "IPv4", (u64)-1, 4408fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, 4418fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 4428fb4bc6fSJiri Pirko ¶ms); 4438fb4bc6fSJiri Pirko if (err) { 4448fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 top resource\n"); 4458fb4bc6fSJiri Pirko goto out; 4468fb4bc6fSJiri Pirko } 4478fb4bc6fSJiri Pirko 448012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib", (u64)-1, 4498fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 4508fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 4518fb4bc6fSJiri Pirko if (err) { 4528fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB resource\n"); 4538fb4bc6fSJiri Pirko return err; 4548fb4bc6fSJiri Pirko } 4558fb4bc6fSJiri Pirko 456012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib-rules", (u64)-1, 4578fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 4588fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 4598fb4bc6fSJiri Pirko if (err) { 4608fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB rules resource\n"); 4618fb4bc6fSJiri Pirko return err; 4628fb4bc6fSJiri Pirko } 4638fb4bc6fSJiri Pirko 4648fb4bc6fSJiri Pirko /* Resources for IPv6 */ 465012ec02aSJiri Pirko err = devl_resource_register(devlink, "IPv6", (u64)-1, 4668fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, 4678fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 4688fb4bc6fSJiri Pirko ¶ms); 4698fb4bc6fSJiri Pirko if (err) { 4708fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 top resource\n"); 4718fb4bc6fSJiri Pirko goto out; 4728fb4bc6fSJiri Pirko } 4738fb4bc6fSJiri Pirko 474012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib", (u64)-1, 4758fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 4768fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 4778fb4bc6fSJiri Pirko if (err) { 4788fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB resource\n"); 4798fb4bc6fSJiri Pirko return err; 4808fb4bc6fSJiri Pirko } 4818fb4bc6fSJiri Pirko 482012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib-rules", (u64)-1, 4838fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 4848fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 4858fb4bc6fSJiri Pirko if (err) { 4868fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB rules resource\n"); 4878fb4bc6fSJiri Pirko return err; 4888fb4bc6fSJiri Pirko } 4898fb4bc6fSJiri Pirko 49035266255SIdo Schimmel /* Resources for nexthops */ 491012ec02aSJiri Pirko err = devl_resource_register(devlink, "nexthops", (u64)-1, 49235266255SIdo Schimmel NSIM_RESOURCE_NEXTHOPS, 49335266255SIdo Schimmel DEVLINK_RESOURCE_ID_PARENT_TOP, 49435266255SIdo Schimmel ¶ms); 49535266255SIdo Schimmel 4968fb4bc6fSJiri Pirko out: 4978fb4bc6fSJiri Pirko return err; 4988fb4bc6fSJiri Pirko } 4998fb4bc6fSJiri Pirko 500150e8f8aSJiri Pirko enum nsim_devlink_param_id { 501150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 502150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 503150e8f8aSJiri Pirko }; 504150e8f8aSJiri Pirko 505150e8f8aSJiri Pirko static const struct devlink_param nsim_devlink_params[] = { 506150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC(MAX_MACS, 507150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 508150e8f8aSJiri Pirko NULL, NULL, NULL), 509150e8f8aSJiri Pirko DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1, 510150e8f8aSJiri Pirko "test1", DEVLINK_PARAM_TYPE_BOOL, 511150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 512150e8f8aSJiri Pirko NULL, NULL, NULL), 513150e8f8aSJiri Pirko }; 514150e8f8aSJiri Pirko 515150e8f8aSJiri Pirko static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev, 516150e8f8aSJiri Pirko struct devlink *devlink) 517150e8f8aSJiri Pirko { 518150e8f8aSJiri Pirko union devlink_param_value value; 519150e8f8aSJiri Pirko 520150e8f8aSJiri Pirko value.vu32 = nsim_dev->max_macs; 521150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 522150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 523150e8f8aSJiri Pirko value); 524150e8f8aSJiri Pirko value.vbool = nsim_dev->test1; 525150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 526150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 527150e8f8aSJiri Pirko value); 528150e8f8aSJiri Pirko } 529150e8f8aSJiri Pirko 530150e8f8aSJiri Pirko static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink) 531150e8f8aSJiri Pirko { 532150e8f8aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 533150e8f8aSJiri Pirko union devlink_param_value saved_value; 534150e8f8aSJiri Pirko int err; 535150e8f8aSJiri Pirko 536150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 537150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 538150e8f8aSJiri Pirko &saved_value); 539150e8f8aSJiri Pirko if (!err) 540150e8f8aSJiri Pirko nsim_dev->max_macs = saved_value.vu32; 541150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 542150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 543150e8f8aSJiri Pirko &saved_value); 544150e8f8aSJiri Pirko if (!err) 545150e8f8aSJiri Pirko nsim_dev->test1 = saved_value.vbool; 546150e8f8aSJiri Pirko } 547150e8f8aSJiri Pirko 5484418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX 16 5494418f862SJiri Pirko 550e8937681SJacob Keller static const struct devlink_region_ops dummy_region_ops = { 551e8937681SJacob Keller .name = "dummy", 552a0a09f6bSJacob Keller .destructor = &kfree, 5533fe0fd53SJacob Keller .snapshot = nsim_dev_take_snapshot, 554e8937681SJacob Keller }; 555e8937681SJacob Keller 5564418f862SJiri Pirko static int nsim_dev_dummy_region_init(struct nsim_dev *nsim_dev, 5574418f862SJiri Pirko struct devlink *devlink) 5584418f862SJiri Pirko { 5594418f862SJiri Pirko nsim_dev->dummy_region = 560012ec02aSJiri Pirko devl_region_create(devlink, &dummy_region_ops, 5614418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX, 5624418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SIZE); 5634418f862SJiri Pirko return PTR_ERR_OR_ZERO(nsim_dev->dummy_region); 5644418f862SJiri Pirko } 5654418f862SJiri Pirko 5664418f862SJiri Pirko static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev) 5674418f862SJiri Pirko { 568012ec02aSJiri Pirko devl_region_destroy(nsim_dev->dummy_region); 5694418f862SJiri Pirko } 5704418f862SJiri Pirko 571aff3a925SJakub Kicinski static int 572aff3a925SJakub Kicinski __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 573aff3a925SJakub Kicinski unsigned int port_index); 574160dc373SDmytro Linkin static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port); 5751c401078SJakub Kicinski 5761c401078SJakub Kicinski static int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, 5771c401078SJakub Kicinski struct netlink_ext_ack *extack) 578160dc373SDmytro Linkin { 579885226f5SDmytro Linkin struct devlink *devlink = priv_to_devlink(nsim_dev); 580160dc373SDmytro Linkin struct nsim_dev_port *nsim_dev_port, *tmp; 581160dc373SDmytro Linkin 582aff3a925SJakub Kicinski devl_rate_nodes_destroy(devlink); 583160dc373SDmytro Linkin list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) 584160dc373SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 585160dc373SDmytro Linkin __nsim_dev_port_del(nsim_dev_port); 586160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 587160dc373SDmytro Linkin return 0; 588160dc373SDmytro Linkin } 589160dc373SDmytro Linkin 5901c401078SJakub Kicinski static int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev, 5911c401078SJakub Kicinski struct netlink_ext_ack *extack) 592160dc373SDmytro Linkin { 593aff3a925SJakub Kicinski struct nsim_dev_port *nsim_dev_port, *tmp; 594160dc373SDmytro Linkin int i, err; 595160dc373SDmytro Linkin 5965e388f3dSJakub Kicinski for (i = 0; i < nsim_dev_get_vfs(nsim_dev); i++) { 597aff3a925SJakub Kicinski err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_VF, i); 598160dc373SDmytro Linkin if (err) { 599160dc373SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports"); 600160dc373SDmytro Linkin pr_err("Failed to initialize VF id=%d. %d.\n", i, err); 601160dc373SDmytro Linkin goto err_port_add_vfs; 602160dc373SDmytro Linkin } 603160dc373SDmytro Linkin } 604160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 605160dc373SDmytro Linkin return 0; 606160dc373SDmytro Linkin 607160dc373SDmytro Linkin err_port_add_vfs: 608aff3a925SJakub Kicinski list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) 609aff3a925SJakub Kicinski if (nsim_dev_port_is_vf(nsim_dev_port)) 610aff3a925SJakub Kicinski __nsim_dev_port_del(nsim_dev_port); 611160dc373SDmytro Linkin return err; 612160dc373SDmytro Linkin } 613160dc373SDmytro Linkin 614160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, 615160dc373SDmytro Linkin struct netlink_ext_ack *extack) 616160dc373SDmytro Linkin { 617160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 618160dc373SDmytro Linkin 619160dc373SDmytro Linkin if (mode == nsim_dev->esw_mode) 62014e426bfSJakub Kicinski return 0; 621160dc373SDmytro Linkin 622160dc373SDmytro Linkin if (mode == DEVLINK_ESWITCH_MODE_LEGACY) 62314e426bfSJakub Kicinski return nsim_esw_legacy_enable(nsim_dev, extack); 62414e426bfSJakub Kicinski if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) 62514e426bfSJakub Kicinski return nsim_esw_switchdev_enable(nsim_dev, extack); 626160dc373SDmytro Linkin 62714e426bfSJakub Kicinski return -EINVAL; 628160dc373SDmytro Linkin } 629160dc373SDmytro Linkin 630160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) 631160dc373SDmytro Linkin { 632160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 633160dc373SDmytro Linkin 634160dc373SDmytro Linkin *mode = nsim_dev->esw_mode; 635160dc373SDmytro Linkin return 0; 636160dc373SDmytro Linkin } 637160dc373SDmytro Linkin 638da58f90fSIdo Schimmel struct nsim_trap_item { 639da58f90fSIdo Schimmel void *trap_ctx; 640da58f90fSIdo Schimmel enum devlink_trap_action action; 641da58f90fSIdo Schimmel }; 642da58f90fSIdo Schimmel 643da58f90fSIdo Schimmel struct nsim_trap_data { 644da58f90fSIdo Schimmel struct delayed_work trap_report_dw; 645da58f90fSIdo Schimmel struct nsim_trap_item *trap_items_arr; 646ad188458SIdo Schimmel u64 *trap_policers_cnt_arr; 647a7b3527aSOleksandr Mazur u64 trap_pkt_cnt; 648da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 649da58f90fSIdo Schimmel spinlock_t trap_lock; /* Protects trap_items_arr */ 650da58f90fSIdo Schimmel }; 651da58f90fSIdo Schimmel 6529e087457SIdo Schimmel /* All driver-specific traps must be documented in 65304e4272cSJacob Keller * Documentation/networking/devlink/netdevsim.rst 6549e087457SIdo Schimmel */ 655da58f90fSIdo Schimmel enum { 656da58f90fSIdo Schimmel NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX, 657da58f90fSIdo Schimmel NSIM_TRAP_ID_FID_MISS, 658da58f90fSIdo Schimmel }; 659da58f90fSIdo Schimmel 660da58f90fSIdo Schimmel #define NSIM_TRAP_NAME_FID_MISS "fid_miss" 661da58f90fSIdo Schimmel 662da58f90fSIdo Schimmel #define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT 663da58f90fSIdo Schimmel 664da58f90fSIdo Schimmel #define NSIM_TRAP_DROP(_id, _group_id) \ 665da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 666107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 667da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 668d3cbb907SJiri Pirko #define NSIM_TRAP_DROP_EXT(_id, _group_id, _metadata) \ 669d3cbb907SJiri Pirko DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 670107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 671d3cbb907SJiri Pirko NSIM_TRAP_METADATA | (_metadata)) 672da58f90fSIdo Schimmel #define NSIM_TRAP_EXCEPTION(_id, _group_id) \ 673da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ 674107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 675da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 67618979367SIdo Schimmel #define NSIM_TRAP_CONTROL(_id, _group_id, _action) \ 67718979367SIdo Schimmel DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ 67818979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 67918979367SIdo Schimmel NSIM_TRAP_METADATA) 680da58f90fSIdo Schimmel #define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id) \ 681da58f90fSIdo Schimmel DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id, \ 682da58f90fSIdo Schimmel NSIM_TRAP_NAME_##_id, \ 683107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 684da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 685da58f90fSIdo Schimmel 686ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_RATE 1 687ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_RATE 8000 688ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_BURST 8 689ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_BURST 65536 690ad188458SIdo Schimmel 691ad188458SIdo Schimmel #define NSIM_TRAP_POLICER(_id, _rate, _burst) \ 692ad188458SIdo Schimmel DEVLINK_TRAP_POLICER(_id, _rate, _burst, \ 693ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_RATE, \ 694ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_RATE, \ 695ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_BURST, \ 696ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_BURST) 697ad188458SIdo Schimmel 698ad188458SIdo Schimmel static const struct devlink_trap_policer nsim_trap_policers_arr[] = { 699ad188458SIdo Schimmel NSIM_TRAP_POLICER(1, 1000, 128), 700ad188458SIdo Schimmel NSIM_TRAP_POLICER(2, 2000, 256), 701ad188458SIdo Schimmel NSIM_TRAP_POLICER(3, 3000, 512), 702ad188458SIdo Schimmel }; 703ad188458SIdo Schimmel 704b29545d8SIdo Schimmel static const struct devlink_trap_group nsim_trap_groups_arr[] = { 705f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), 706f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), 70785176f19SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), 708f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 2), 709f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 3), 71018979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 3), 711b29545d8SIdo Schimmel }; 712b29545d8SIdo Schimmel 713da58f90fSIdo Schimmel static const struct devlink_trap nsim_traps_arr[] = { 714da58f90fSIdo Schimmel NSIM_TRAP_DROP(SMAC_MC, L2_DROPS), 715da58f90fSIdo Schimmel NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 716da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 717da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 718da58f90fSIdo Schimmel NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 719da58f90fSIdo Schimmel NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 720da58f90fSIdo Schimmel NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS), 721da58f90fSIdo Schimmel NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 72285176f19SIdo Schimmel NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), 723da58f90fSIdo Schimmel NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS), 724d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, 725d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 726d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, 727d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 72818979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 72918979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, TRAP), 730da58f90fSIdo Schimmel }; 731da58f90fSIdo Schimmel 732da58f90fSIdo Schimmel #define NSIM_TRAP_L4_DATA_LEN 100 733da58f90fSIdo Schimmel 734da58f90fSIdo Schimmel static struct sk_buff *nsim_dev_trap_skb_build(void) 735da58f90fSIdo Schimmel { 736da58f90fSIdo Schimmel int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN; 737da58f90fSIdo Schimmel struct sk_buff *skb; 738da58f90fSIdo Schimmel struct udphdr *udph; 739da58f90fSIdo Schimmel struct ethhdr *eth; 740da58f90fSIdo Schimmel struct iphdr *iph; 741da58f90fSIdo Schimmel 742da58f90fSIdo Schimmel skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 743da58f90fSIdo Schimmel if (!skb) 744da58f90fSIdo Schimmel return NULL; 745da58f90fSIdo Schimmel tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len; 746da58f90fSIdo Schimmel 74758a406deSIdo Schimmel skb_reset_mac_header(skb); 748da58f90fSIdo Schimmel eth = skb_put(skb, sizeof(struct ethhdr)); 749da58f90fSIdo Schimmel eth_random_addr(eth->h_dest); 750da58f90fSIdo Schimmel eth_random_addr(eth->h_source); 751da58f90fSIdo Schimmel eth->h_proto = htons(ETH_P_IP); 752da58f90fSIdo Schimmel skb->protocol = htons(ETH_P_IP); 753da58f90fSIdo Schimmel 75458a406deSIdo Schimmel skb_set_network_header(skb, skb->len); 755da58f90fSIdo Schimmel iph = skb_put(skb, sizeof(struct iphdr)); 756da58f90fSIdo Schimmel iph->protocol = IPPROTO_UDP; 757da58f90fSIdo Schimmel iph->saddr = in_aton("192.0.2.1"); 758da58f90fSIdo Schimmel iph->daddr = in_aton("198.51.100.1"); 759da58f90fSIdo Schimmel iph->version = 0x4; 760da58f90fSIdo Schimmel iph->frag_off = 0; 761da58f90fSIdo Schimmel iph->ihl = 0x5; 762da58f90fSIdo Schimmel iph->tot_len = htons(tot_len); 763da58f90fSIdo Schimmel iph->ttl = 100; 764d9bd6d27SYueHaibing iph->check = 0; 765d9bd6d27SYueHaibing iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 766da58f90fSIdo Schimmel 76758a406deSIdo Schimmel skb_set_transport_header(skb, skb->len); 768da58f90fSIdo Schimmel udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len); 769da58f90fSIdo Schimmel get_random_bytes(&udph->source, sizeof(u16)); 770da58f90fSIdo Schimmel get_random_bytes(&udph->dest, sizeof(u16)); 771da58f90fSIdo Schimmel udph->len = htons(sizeof(struct udphdr) + data_len); 772da58f90fSIdo Schimmel 773da58f90fSIdo Schimmel return skb; 774da58f90fSIdo Schimmel } 775da58f90fSIdo Schimmel 776da58f90fSIdo Schimmel static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port) 777da58f90fSIdo Schimmel { 778da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 779da58f90fSIdo Schimmel struct devlink *devlink = priv_to_devlink(nsim_dev); 780da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 781da58f90fSIdo Schimmel int i; 782da58f90fSIdo Schimmel 783da58f90fSIdo Schimmel nsim_trap_data = nsim_dev->trap_data; 784da58f90fSIdo Schimmel 785da58f90fSIdo Schimmel spin_lock(&nsim_trap_data->trap_lock); 786da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 787d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie = NULL; 788da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 789da58f90fSIdo Schimmel struct sk_buff *skb; 790d3cbb907SJiri Pirko bool has_fa_cookie; 791d3cbb907SJiri Pirko 792d3cbb907SJiri Pirko has_fa_cookie = nsim_traps_arr[i].metadata_cap & 793d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE; 794da58f90fSIdo Schimmel 795da58f90fSIdo Schimmel nsim_trap_item = &nsim_trap_data->trap_items_arr[i]; 796da58f90fSIdo Schimmel if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP) 797da58f90fSIdo Schimmel continue; 798da58f90fSIdo Schimmel 799da58f90fSIdo Schimmel skb = nsim_dev_trap_skb_build(); 800da58f90fSIdo Schimmel if (!skb) 801da58f90fSIdo Schimmel continue; 802da58f90fSIdo Schimmel skb->dev = nsim_dev_port->ns->netdev; 803da58f90fSIdo Schimmel 804da58f90fSIdo Schimmel /* Trapped packets are usually passed to devlink in softIRQ, 805da58f90fSIdo Schimmel * but in this case they are generated in a workqueue. Disable 806da58f90fSIdo Schimmel * softIRQs to prevent lockdep from complaining about 807da58f90fSIdo Schimmel * "incosistent lock state". 808da58f90fSIdo Schimmel */ 809d3cbb907SJiri Pirko 810d3cbb907SJiri Pirko spin_lock_bh(&nsim_dev->fa_cookie_lock); 811d3cbb907SJiri Pirko fa_cookie = has_fa_cookie ? nsim_dev->fa_cookie : NULL; 812da58f90fSIdo Schimmel devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx, 813d3cbb907SJiri Pirko &nsim_dev_port->devlink_port, fa_cookie); 814d3cbb907SJiri Pirko spin_unlock_bh(&nsim_dev->fa_cookie_lock); 815da58f90fSIdo Schimmel consume_skb(skb); 816da58f90fSIdo Schimmel } 817da58f90fSIdo Schimmel spin_unlock(&nsim_trap_data->trap_lock); 818da58f90fSIdo Schimmel } 819da58f90fSIdo Schimmel 820da58f90fSIdo Schimmel #define NSIM_TRAP_REPORT_INTERVAL_MS 100 821da58f90fSIdo Schimmel 822da58f90fSIdo Schimmel static void nsim_dev_trap_report_work(struct work_struct *work) 823da58f90fSIdo Schimmel { 824da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 825da58f90fSIdo Schimmel struct nsim_dev_port *nsim_dev_port; 826da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 827da58f90fSIdo Schimmel 828da58f90fSIdo Schimmel nsim_trap_data = container_of(work, struct nsim_trap_data, 829da58f90fSIdo Schimmel trap_report_dw.work); 830da58f90fSIdo Schimmel nsim_dev = nsim_trap_data->nsim_dev; 831da58f90fSIdo Schimmel 832da58f90fSIdo Schimmel /* For each running port and enabled packet trap, generate a UDP 833da58f90fSIdo Schimmel * packet with a random 5-tuple and report it. 834da58f90fSIdo Schimmel */ 835012ec02aSJiri Pirko if (!devl_trylock(priv_to_devlink(nsim_dev))) { 836012ec02aSJiri Pirko schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 0); 837012ec02aSJiri Pirko return; 838012ec02aSJiri Pirko } 839012ec02aSJiri Pirko 840da58f90fSIdo Schimmel list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) { 841da58f90fSIdo Schimmel if (!netif_running(nsim_dev_port->ns->netdev)) 842da58f90fSIdo Schimmel continue; 843da58f90fSIdo Schimmel 844da58f90fSIdo Schimmel nsim_dev_trap_report(nsim_dev_port); 845da58f90fSIdo Schimmel } 84676eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 847da58f90fSIdo Schimmel 848da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 849da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 850da58f90fSIdo Schimmel } 851da58f90fSIdo Schimmel 852da58f90fSIdo Schimmel static int nsim_dev_traps_init(struct devlink *devlink) 853da58f90fSIdo Schimmel { 854ad188458SIdo Schimmel size_t policers_count = ARRAY_SIZE(nsim_trap_policers_arr); 855da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 856da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 857da58f90fSIdo Schimmel int err; 858da58f90fSIdo Schimmel 859da58f90fSIdo Schimmel nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL); 860da58f90fSIdo Schimmel if (!nsim_trap_data) 861da58f90fSIdo Schimmel return -ENOMEM; 862da58f90fSIdo Schimmel 863da58f90fSIdo Schimmel nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr), 864da58f90fSIdo Schimmel sizeof(struct nsim_trap_item), 865da58f90fSIdo Schimmel GFP_KERNEL); 866da58f90fSIdo Schimmel if (!nsim_trap_data->trap_items_arr) { 867da58f90fSIdo Schimmel err = -ENOMEM; 868da58f90fSIdo Schimmel goto err_trap_data_free; 869da58f90fSIdo Schimmel } 870da58f90fSIdo Schimmel 871ad188458SIdo Schimmel nsim_trap_data->trap_policers_cnt_arr = kcalloc(policers_count, 872ad188458SIdo Schimmel sizeof(u64), 873ad188458SIdo Schimmel GFP_KERNEL); 874ad188458SIdo Schimmel if (!nsim_trap_data->trap_policers_cnt_arr) { 875ad188458SIdo Schimmel err = -ENOMEM; 876ad188458SIdo Schimmel goto err_trap_items_free; 877ad188458SIdo Schimmel } 878ad188458SIdo Schimmel 879da58f90fSIdo Schimmel /* The lock is used to protect the action state of the registered 880da58f90fSIdo Schimmel * traps. The value is written by user and read in delayed work when 881da58f90fSIdo Schimmel * iterating over all the traps. 882da58f90fSIdo Schimmel */ 883da58f90fSIdo Schimmel spin_lock_init(&nsim_trap_data->trap_lock); 884da58f90fSIdo Schimmel nsim_trap_data->nsim_dev = nsim_dev; 885da58f90fSIdo Schimmel nsim_dev->trap_data = nsim_trap_data; 886da58f90fSIdo Schimmel 887012ec02aSJiri Pirko err = devl_trap_policers_register(devlink, nsim_trap_policers_arr, 888ad188458SIdo Schimmel policers_count); 889ad188458SIdo Schimmel if (err) 890ad188458SIdo Schimmel goto err_trap_policers_cnt_free; 891ad188458SIdo Schimmel 892012ec02aSJiri Pirko err = devl_trap_groups_register(devlink, nsim_trap_groups_arr, 893b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 894b29545d8SIdo Schimmel if (err) 895ad188458SIdo Schimmel goto err_trap_policers_unregister; 896b29545d8SIdo Schimmel 897012ec02aSJiri Pirko err = devl_traps_register(devlink, nsim_traps_arr, 898da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr), NULL); 899da58f90fSIdo Schimmel if (err) 900b29545d8SIdo Schimmel goto err_trap_groups_unregister; 901da58f90fSIdo Schimmel 902da58f90fSIdo Schimmel INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw, 903da58f90fSIdo Schimmel nsim_dev_trap_report_work); 904da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 905da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 906da58f90fSIdo Schimmel 907da58f90fSIdo Schimmel return 0; 908da58f90fSIdo Schimmel 909b29545d8SIdo Schimmel err_trap_groups_unregister: 910012ec02aSJiri Pirko devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, 911b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 912ad188458SIdo Schimmel err_trap_policers_unregister: 913012ec02aSJiri Pirko devl_trap_policers_unregister(devlink, nsim_trap_policers_arr, 914ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 915ad188458SIdo Schimmel err_trap_policers_cnt_free: 916ad188458SIdo Schimmel kfree(nsim_trap_data->trap_policers_cnt_arr); 917da58f90fSIdo Schimmel err_trap_items_free: 918da58f90fSIdo Schimmel kfree(nsim_trap_data->trap_items_arr); 919da58f90fSIdo Schimmel err_trap_data_free: 920da58f90fSIdo Schimmel kfree(nsim_trap_data); 921da58f90fSIdo Schimmel return err; 922da58f90fSIdo Schimmel } 923da58f90fSIdo Schimmel 924da58f90fSIdo Schimmel static void nsim_dev_traps_exit(struct devlink *devlink) 925da58f90fSIdo Schimmel { 926da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 927da58f90fSIdo Schimmel 92876eea6c2SJakub Kicinski /* caution, trap work takes devlink lock */ 929da58f90fSIdo Schimmel cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw); 930012ec02aSJiri Pirko devl_traps_unregister(devlink, nsim_traps_arr, 931da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr)); 932012ec02aSJiri Pirko devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, 933b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 934012ec02aSJiri Pirko devl_trap_policers_unregister(devlink, nsim_trap_policers_arr, 935ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 936ad188458SIdo Schimmel kfree(nsim_dev->trap_data->trap_policers_cnt_arr); 937da58f90fSIdo Schimmel kfree(nsim_dev->trap_data->trap_items_arr); 938da58f90fSIdo Schimmel kfree(nsim_dev->trap_data); 939da58f90fSIdo Schimmel } 940da58f90fSIdo Schimmel 94175ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 94275ba029fSJiri Pirko struct netlink_ext_ack *extack); 94375ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); 94475ba029fSJiri Pirko 945070c63f2SJiri Pirko static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, 946dc64cc7cSMoshe Shemesh enum devlink_reload_action action, enum devlink_reload_limit limit, 947dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 94897691069SJiri Pirko { 94975ba029fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 95023809a72SLeon Romanovsky 951155ddfc5SJiri Pirko if (nsim_dev->dont_allow_reload) { 952155ddfc5SJiri Pirko /* For testing purposes, user set debugfs dont_allow_reload 953155ddfc5SJiri Pirko * value to true. So forbid it. 954155ddfc5SJiri Pirko */ 955f9867b51SColin Ian King NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); 956155ddfc5SJiri Pirko return -EOPNOTSUPP; 957155ddfc5SJiri Pirko } 958155ddfc5SJiri Pirko 95975ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 96097691069SJiri Pirko return 0; 96197691069SJiri Pirko } 96297691069SJiri Pirko 963ccdf0721SMoshe Shemesh static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action, 964dc64cc7cSMoshe Shemesh enum devlink_reload_limit limit, u32 *actions_performed, 965dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 9668fb4bc6fSJiri Pirko { 967a5facc4cSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 9685c0418edSLeon Romanovsky int ret; 9695c0418edSLeon Romanovsky 970155ddfc5SJiri Pirko if (nsim_dev->fail_reload) { 971155ddfc5SJiri Pirko /* For testing purposes, user set debugfs fail_reload 972155ddfc5SJiri Pirko * value to true. Fail right away. 973155ddfc5SJiri Pirko */ 974155ddfc5SJiri Pirko NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); 975155ddfc5SJiri Pirko return -EINVAL; 976155ddfc5SJiri Pirko } 977155ddfc5SJiri Pirko 978ccdf0721SMoshe Shemesh *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 9795c0418edSLeon Romanovsky ret = nsim_dev_reload_create(nsim_dev, extack); 9805c0418edSLeon Romanovsky return ret; 9818fb4bc6fSJiri Pirko } 9828fb4bc6fSJiri Pirko 9838e23cc03SJiri Pirko static int nsim_dev_info_get(struct devlink *devlink, 9848e23cc03SJiri Pirko struct devlink_info_req *req, 9858e23cc03SJiri Pirko struct netlink_ext_ack *extack) 9868e23cc03SJiri Pirko { 9870c198975SJiri Pirko int err; 9880c198975SJiri Pirko 9890c198975SJiri Pirko err = devlink_info_driver_name_put(req, DRV_NAME); 9900c198975SJiri Pirko if (err) 9910c198975SJiri Pirko return err; 9920c198975SJiri Pirko err = devlink_info_version_stored_put_ext(req, "fw.mgmt", "10.20.30", 9930c198975SJiri Pirko DEVLINK_INFO_VERSION_TYPE_COMPONENT); 9940c198975SJiri Pirko if (err) 9950c198975SJiri Pirko return err; 9960c198975SJiri Pirko return devlink_info_version_running_put_ext(req, "fw.mgmt", "10.20.30", 9970c198975SJiri Pirko DEVLINK_INFO_VERSION_TYPE_COMPONENT); 9988e23cc03SJiri Pirko } 9998e23cc03SJiri Pirko 1000fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000 1001fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 1002fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 1003fa4dfc4aSJiri Pirko 1004bc75c054SJacob Keller static int nsim_dev_flash_update(struct devlink *devlink, 1005bc75c054SJacob Keller struct devlink_flash_update_params *params, 1006fa4dfc4aSJiri Pirko struct netlink_ext_ack *extack) 1007fa4dfc4aSJiri Pirko { 1008fa4dfc4aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 1009fa4dfc4aSJiri Pirko int i; 1010fa4dfc4aSJiri Pirko 1011cbb58368SJacob Keller if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0) 1012cbb58368SJacob Keller return -EOPNOTSUPP; 1013cbb58368SJacob Keller 1014fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1015fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, 1016fa4dfc4aSJiri Pirko "Preparing to flash", 1017bc75c054SJacob Keller params->component, 0, 0); 1018fa4dfc4aSJiri Pirko } 1019fa4dfc4aSJiri Pirko 1020fa4dfc4aSJiri Pirko for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 1021fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) 1022fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1023bc75c054SJacob Keller params->component, 1024fa4dfc4aSJiri Pirko i * NSIM_DEV_FLASH_CHUNK_SIZE, 1025fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1026fa4dfc4aSJiri Pirko msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 1027fa4dfc4aSJiri Pirko } 1028fa4dfc4aSJiri Pirko 1029fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1030fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1031bc75c054SJacob Keller params->component, 1032fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE, 1033fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1034b311b001SShannon Nelson devlink_flash_update_timeout_notify(devlink, "Flash select", 1035bc75c054SJacob Keller params->component, 81); 1036fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing done", 1037bc75c054SJacob Keller params->component, 0, 0); 1038fa4dfc4aSJiri Pirko } 1039fa4dfc4aSJiri Pirko 1040fa4dfc4aSJiri Pirko return 0; 1041fa4dfc4aSJiri Pirko } 1042fa4dfc4aSJiri Pirko 1043da58f90fSIdo Schimmel static struct nsim_trap_item * 1044da58f90fSIdo Schimmel nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id) 1045da58f90fSIdo Schimmel { 1046da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data; 1047da58f90fSIdo Schimmel int i; 1048da58f90fSIdo Schimmel 1049da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 1050da58f90fSIdo Schimmel if (nsim_traps_arr[i].id == trap_id) 1051da58f90fSIdo Schimmel return &nsim_trap_data->trap_items_arr[i]; 1052da58f90fSIdo Schimmel } 1053da58f90fSIdo Schimmel 1054da58f90fSIdo Schimmel return NULL; 1055da58f90fSIdo Schimmel } 1056da58f90fSIdo Schimmel 1057da58f90fSIdo Schimmel static int nsim_dev_devlink_trap_init(struct devlink *devlink, 1058da58f90fSIdo Schimmel const struct devlink_trap *trap, 1059da58f90fSIdo Schimmel void *trap_ctx) 1060da58f90fSIdo Schimmel { 1061da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1062da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1063da58f90fSIdo Schimmel 1064da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1065da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1066da58f90fSIdo Schimmel return -ENOENT; 1067da58f90fSIdo Schimmel 1068da58f90fSIdo Schimmel nsim_trap_item->trap_ctx = trap_ctx; 1069da58f90fSIdo Schimmel nsim_trap_item->action = trap->init_action; 1070da58f90fSIdo Schimmel 1071da58f90fSIdo Schimmel return 0; 1072da58f90fSIdo Schimmel } 1073da58f90fSIdo Schimmel 1074da58f90fSIdo Schimmel static int 1075da58f90fSIdo Schimmel nsim_dev_devlink_trap_action_set(struct devlink *devlink, 1076da58f90fSIdo Schimmel const struct devlink_trap *trap, 1077c88e11e0SIdo Schimmel enum devlink_trap_action action, 1078c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 1079da58f90fSIdo Schimmel { 1080da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1081da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1082da58f90fSIdo Schimmel 1083da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1084da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1085da58f90fSIdo Schimmel return -ENOENT; 1086da58f90fSIdo Schimmel 1087da58f90fSIdo Schimmel spin_lock(&nsim_dev->trap_data->trap_lock); 1088da58f90fSIdo Schimmel nsim_trap_item->action = action; 1089da58f90fSIdo Schimmel spin_unlock(&nsim_dev->trap_data->trap_lock); 1090da58f90fSIdo Schimmel 1091da58f90fSIdo Schimmel return 0; 1092da58f90fSIdo Schimmel } 1093da58f90fSIdo Schimmel 1094ad188458SIdo Schimmel static int 10950dc8249aSIdo Schimmel nsim_dev_devlink_trap_group_set(struct devlink *devlink, 10960dc8249aSIdo Schimmel const struct devlink_trap_group *group, 1097c88e11e0SIdo Schimmel const struct devlink_trap_policer *policer, 1098c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 10990dc8249aSIdo Schimmel { 11000dc8249aSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 11010dc8249aSIdo Schimmel 11020dc8249aSIdo Schimmel if (nsim_dev->fail_trap_group_set) 11030dc8249aSIdo Schimmel return -EINVAL; 11040dc8249aSIdo Schimmel 11050dc8249aSIdo Schimmel return 0; 11060dc8249aSIdo Schimmel } 11070dc8249aSIdo Schimmel 11080dc8249aSIdo Schimmel static int 1109ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_set(struct devlink *devlink, 1110ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1111ad188458SIdo Schimmel u64 rate, u64 burst, 1112ad188458SIdo Schimmel struct netlink_ext_ack *extack) 1113ad188458SIdo Schimmel { 1114ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1115ad188458SIdo Schimmel 1116ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_set) { 1117ad188458SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes"); 1118ad188458SIdo Schimmel return -EINVAL; 1119ad188458SIdo Schimmel } 1120ad188458SIdo Schimmel 1121ad188458SIdo Schimmel return 0; 1122ad188458SIdo Schimmel } 1123ad188458SIdo Schimmel 1124ad188458SIdo Schimmel static int 1125ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink, 1126ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1127ad188458SIdo Schimmel u64 *p_drops) 1128ad188458SIdo Schimmel { 1129ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1130ad188458SIdo Schimmel u64 *cnt; 1131ad188458SIdo Schimmel 1132ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_counter_get) 1133ad188458SIdo Schimmel return -EINVAL; 1134ad188458SIdo Schimmel 1135ad188458SIdo Schimmel cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1]; 1136be43224fSIdo Schimmel *p_drops = (*cnt)++; 1137ad188458SIdo Schimmel 1138ad188458SIdo Schimmel return 0; 1139ad188458SIdo Schimmel } 1140ad188458SIdo Schimmel 1141605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_MAX 5000 /* Mbps */ 1142605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_UNIT 125000 /* 1 Mbps given in bytes/sec to avoid 1143605c4f8fSDmytro Linkin * u64 overflow during conversion from 1144605c4f8fSDmytro Linkin * bytes to bits. 1145605c4f8fSDmytro Linkin */ 1146605c4f8fSDmytro Linkin 1147605c4f8fSDmytro Linkin static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack) 1148605c4f8fSDmytro Linkin { 1149605c4f8fSDmytro Linkin u64 val; 1150605c4f8fSDmytro Linkin u32 rem; 1151605c4f8fSDmytro Linkin 1152605c4f8fSDmytro Linkin val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem); 1153605c4f8fSDmytro Linkin if (rem) { 1154605c4f8fSDmytro Linkin pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n", 1155605c4f8fSDmytro Linkin name, *rate); 1156605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps."); 1157605c4f8fSDmytro Linkin return -EINVAL; 1158605c4f8fSDmytro Linkin } 1159605c4f8fSDmytro Linkin 1160605c4f8fSDmytro Linkin if (val > NSIM_LINK_SPEED_MAX) { 1161605c4f8fSDmytro Linkin pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n", 1162605c4f8fSDmytro Linkin name, val); 1163605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps."); 1164605c4f8fSDmytro Linkin return -EINVAL; 1165605c4f8fSDmytro Linkin } 1166605c4f8fSDmytro Linkin *rate = val; 1167605c4f8fSDmytro Linkin return 0; 1168605c4f8fSDmytro Linkin } 1169605c4f8fSDmytro Linkin 1170605c4f8fSDmytro Linkin static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1171605c4f8fSDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1172605c4f8fSDmytro Linkin { 1173605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11745e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1175605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1176605c4f8fSDmytro Linkin int err; 1177605c4f8fSDmytro Linkin 1178605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1179605c4f8fSDmytro Linkin if (err) 1180605c4f8fSDmytro Linkin return err; 1181605c4f8fSDmytro Linkin 11825e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].min_tx_rate = tx_share; 1183605c4f8fSDmytro Linkin return 0; 1184605c4f8fSDmytro Linkin } 1185605c4f8fSDmytro Linkin 1186605c4f8fSDmytro Linkin static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1187605c4f8fSDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1188605c4f8fSDmytro Linkin { 1189605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11905e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1191605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1192605c4f8fSDmytro Linkin int err; 1193605c4f8fSDmytro Linkin 1194605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1195605c4f8fSDmytro Linkin if (err) 1196605c4f8fSDmytro Linkin return err; 1197605c4f8fSDmytro Linkin 11985e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].max_tx_rate = tx_max; 1199605c4f8fSDmytro Linkin return 0; 1200605c4f8fSDmytro Linkin } 1201605c4f8fSDmytro Linkin 1202885226f5SDmytro Linkin struct nsim_rate_node { 1203885226f5SDmytro Linkin struct dentry *ddir; 1204f3d101b4SDmytro Linkin struct dentry *rate_parent; 1205f3d101b4SDmytro Linkin char *parent_name; 1206885226f5SDmytro Linkin u16 tx_share; 1207885226f5SDmytro Linkin u16 tx_max; 1208885226f5SDmytro Linkin }; 1209885226f5SDmytro Linkin 1210885226f5SDmytro Linkin static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1211885226f5SDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1212885226f5SDmytro Linkin { 1213885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1214885226f5SDmytro Linkin int err; 1215885226f5SDmytro Linkin 1216885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1217885226f5SDmytro Linkin if (err) 1218885226f5SDmytro Linkin return err; 1219885226f5SDmytro Linkin 1220885226f5SDmytro Linkin nsim_node->tx_share = tx_share; 1221885226f5SDmytro Linkin return 0; 1222885226f5SDmytro Linkin } 1223885226f5SDmytro Linkin 1224885226f5SDmytro Linkin static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1225885226f5SDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1226885226f5SDmytro Linkin { 1227885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1228885226f5SDmytro Linkin int err; 1229885226f5SDmytro Linkin 1230885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1231885226f5SDmytro Linkin if (err) 1232885226f5SDmytro Linkin return err; 1233885226f5SDmytro Linkin 1234885226f5SDmytro Linkin nsim_node->tx_max = tx_max; 1235885226f5SDmytro Linkin return 0; 1236885226f5SDmytro Linkin } 1237885226f5SDmytro Linkin 1238885226f5SDmytro Linkin static int nsim_rate_node_new(struct devlink_rate *node, void **priv, 1239885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1240885226f5SDmytro Linkin { 1241885226f5SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(node->devlink); 1242885226f5SDmytro Linkin struct nsim_rate_node *nsim_node; 1243885226f5SDmytro Linkin 1244885226f5SDmytro Linkin if (!nsim_esw_mode_is_switchdev(nsim_dev)) { 1245885226f5SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode."); 1246885226f5SDmytro Linkin return -EOPNOTSUPP; 1247885226f5SDmytro Linkin } 1248885226f5SDmytro Linkin 1249885226f5SDmytro Linkin nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL); 1250885226f5SDmytro Linkin if (!nsim_node) 1251885226f5SDmytro Linkin return -ENOMEM; 1252885226f5SDmytro Linkin 1253885226f5SDmytro Linkin nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir); 12544e744cb8SDan Carpenter 1255885226f5SDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share); 1256885226f5SDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max); 1257f3d101b4SDmytro Linkin nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400, 1258f3d101b4SDmytro Linkin nsim_node->ddir, 1259f3d101b4SDmytro Linkin &nsim_node->parent_name, 1260f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 1261f3d101b4SDmytro Linkin 1262885226f5SDmytro Linkin *priv = nsim_node; 1263885226f5SDmytro Linkin return 0; 1264885226f5SDmytro Linkin } 1265885226f5SDmytro Linkin 1266885226f5SDmytro Linkin static int nsim_rate_node_del(struct devlink_rate *node, void *priv, 1267885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1268885226f5SDmytro Linkin { 1269885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1270885226f5SDmytro Linkin 1271f3d101b4SDmytro Linkin debugfs_remove(nsim_node->rate_parent); 1272885226f5SDmytro Linkin debugfs_remove_recursive(nsim_node->ddir); 1273885226f5SDmytro Linkin kfree(nsim_node); 1274885226f5SDmytro Linkin return 0; 1275885226f5SDmytro Linkin } 1276885226f5SDmytro Linkin 1277f3d101b4SDmytro Linkin static int nsim_rate_leaf_parent_set(struct devlink_rate *child, 1278f3d101b4SDmytro Linkin struct devlink_rate *parent, 1279f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1280f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1281f3d101b4SDmytro Linkin { 1282f3d101b4SDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv_child; 1283f3d101b4SDmytro Linkin 1284f3d101b4SDmytro Linkin if (parent) 1285f3d101b4SDmytro Linkin nsim_dev_port->parent_name = parent->name; 1286f3d101b4SDmytro Linkin else 1287f3d101b4SDmytro Linkin nsim_dev_port->parent_name = NULL; 1288f3d101b4SDmytro Linkin return 0; 1289f3d101b4SDmytro Linkin } 1290f3d101b4SDmytro Linkin 1291f3d101b4SDmytro Linkin static int nsim_rate_node_parent_set(struct devlink_rate *child, 1292f3d101b4SDmytro Linkin struct devlink_rate *parent, 1293f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1294f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1295f3d101b4SDmytro Linkin { 1296f3d101b4SDmytro Linkin struct nsim_rate_node *nsim_node = priv_child; 1297f3d101b4SDmytro Linkin 1298f3d101b4SDmytro Linkin if (parent) 1299f3d101b4SDmytro Linkin nsim_node->parent_name = parent->name; 1300f3d101b4SDmytro Linkin else 1301f3d101b4SDmytro Linkin nsim_node->parent_name = NULL; 1302f3d101b4SDmytro Linkin return 0; 1303f3d101b4SDmytro Linkin } 1304f3d101b4SDmytro Linkin 1305a7b3527aSOleksandr Mazur static int 1306275b51c2SOleksandr Mazur nsim_dev_devlink_trap_drop_counter_get(struct devlink *devlink, 1307a7b3527aSOleksandr Mazur const struct devlink_trap *trap, 1308a7b3527aSOleksandr Mazur u64 *p_drops) 1309a7b3527aSOleksandr Mazur { 1310a7b3527aSOleksandr Mazur struct nsim_dev *nsim_dev = devlink_priv(devlink); 1311a7b3527aSOleksandr Mazur u64 *cnt; 1312a7b3527aSOleksandr Mazur 1313275b51c2SOleksandr Mazur if (nsim_dev->fail_trap_drop_counter_get) 1314a7b3527aSOleksandr Mazur return -EINVAL; 1315a7b3527aSOleksandr Mazur 1316a7b3527aSOleksandr Mazur cnt = &nsim_dev->trap_data->trap_pkt_cnt; 1317a7b3527aSOleksandr Mazur *p_drops = (*cnt)++; 1318a7b3527aSOleksandr Mazur 1319a7b3527aSOleksandr Mazur return 0; 1320a7b3527aSOleksandr Mazur } 1321a7b3527aSOleksandr Mazur 13228fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 1323160dc373SDmytro Linkin .eswitch_mode_set = nsim_devlink_eswitch_mode_set, 1324160dc373SDmytro Linkin .eswitch_mode_get = nsim_devlink_eswitch_mode_get, 1325*f94b6063SJiri Pirko .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, 1326ccdf0721SMoshe Shemesh .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), 132797691069SJiri Pirko .reload_down = nsim_dev_reload_down, 132897691069SJiri Pirko .reload_up = nsim_dev_reload_up, 13298e23cc03SJiri Pirko .info_get = nsim_dev_info_get, 1330fa4dfc4aSJiri Pirko .flash_update = nsim_dev_flash_update, 1331da58f90fSIdo Schimmel .trap_init = nsim_dev_devlink_trap_init, 1332da58f90fSIdo Schimmel .trap_action_set = nsim_dev_devlink_trap_action_set, 13330dc8249aSIdo Schimmel .trap_group_set = nsim_dev_devlink_trap_group_set, 1334ad188458SIdo Schimmel .trap_policer_set = nsim_dev_devlink_trap_policer_set, 1335ad188458SIdo Schimmel .trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get, 1336605c4f8fSDmytro Linkin .rate_leaf_tx_share_set = nsim_leaf_tx_share_set, 1337605c4f8fSDmytro Linkin .rate_leaf_tx_max_set = nsim_leaf_tx_max_set, 1338885226f5SDmytro Linkin .rate_node_tx_share_set = nsim_node_tx_share_set, 1339885226f5SDmytro Linkin .rate_node_tx_max_set = nsim_node_tx_max_set, 1340885226f5SDmytro Linkin .rate_node_new = nsim_rate_node_new, 1341885226f5SDmytro Linkin .rate_node_del = nsim_rate_node_del, 1342f3d101b4SDmytro Linkin .rate_leaf_parent_set = nsim_rate_leaf_parent_set, 1343f3d101b4SDmytro Linkin .rate_node_parent_set = nsim_rate_node_parent_set, 1344275b51c2SOleksandr Mazur .trap_drop_counter_get = nsim_dev_devlink_trap_drop_counter_get, 13458fb4bc6fSJiri Pirko }; 13468fb4bc6fSJiri Pirko 1347150e8f8aSJiri Pirko #define NSIM_DEV_MAX_MACS_DEFAULT 32 1348150e8f8aSJiri Pirko #define NSIM_DEV_TEST1_DEFAULT true 1349150e8f8aSJiri Pirko 1350814b9ce6SDmytro Linkin static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1351794b2c05SJiri Pirko unsigned int port_index) 13528320d145SJiri Pirko { 135371ad8d55SDanielle Ratson struct devlink_port_attrs attrs = {}; 13548320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port; 13558320d145SJiri Pirko struct devlink_port *devlink_port; 13568320d145SJiri Pirko int err; 13578320d145SJiri Pirko 13585e388f3dSJakub Kicinski if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_dev_get_vfs(nsim_dev)) 135992ba1f29SDmytro Linkin return -EINVAL; 136092ba1f29SDmytro Linkin 13618320d145SJiri Pirko nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); 13628320d145SJiri Pirko if (!nsim_dev_port) 13638320d145SJiri Pirko return -ENOMEM; 1364814b9ce6SDmytro Linkin nsim_dev_port->port_index = nsim_dev_port_index(type, port_index); 1365814b9ce6SDmytro Linkin nsim_dev_port->port_type = type; 13668320d145SJiri Pirko 13678320d145SJiri Pirko devlink_port = &nsim_dev_port->devlink_port; 136892ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) { 136971ad8d55SDanielle Ratson attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 137071ad8d55SDanielle Ratson attrs.phys.port_number = port_index + 1; 137192ba1f29SDmytro Linkin } else { 137292ba1f29SDmytro Linkin attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; 137392ba1f29SDmytro Linkin attrs.pci_vf.pf = 0; 137492ba1f29SDmytro Linkin attrs.pci_vf.vf = port_index; 137592ba1f29SDmytro Linkin } 137671ad8d55SDanielle Ratson memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 137771ad8d55SDanielle Ratson attrs.switch_id.id_len = nsim_dev->switch_id.id_len; 137871ad8d55SDanielle Ratson devlink_port_attrs_set(devlink_port, &attrs); 137976eea6c2SJakub Kicinski err = devl_port_register(priv_to_devlink(nsim_dev), devlink_port, 1380814b9ce6SDmytro Linkin nsim_dev_port->port_index); 13818320d145SJiri Pirko if (err) 13828320d145SJiri Pirko goto err_port_free; 13838320d145SJiri Pirko 13848320d145SJiri Pirko err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 13858320d145SJiri Pirko if (err) 13868320d145SJiri Pirko goto err_dl_port_unregister; 13878320d145SJiri Pirko 1388e05b2d14SJiri Pirko nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 1389e05b2d14SJiri Pirko if (IS_ERR(nsim_dev_port->ns)) { 1390e05b2d14SJiri Pirko err = PTR_ERR(nsim_dev_port->ns); 1391e05b2d14SJiri Pirko goto err_port_debugfs_exit; 1392e05b2d14SJiri Pirko } 1393e05b2d14SJiri Pirko 1394885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 139576eea6c2SJakub Kicinski err = devl_rate_leaf_create(&nsim_dev_port->devlink_port, 1396885dfe12SDmytro Linkin nsim_dev_port); 1397885dfe12SDmytro Linkin if (err) 1398885dfe12SDmytro Linkin goto err_nsim_destroy; 1399885dfe12SDmytro Linkin } 1400885dfe12SDmytro Linkin 1401e05b2d14SJiri Pirko devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); 14028320d145SJiri Pirko list_add(&nsim_dev_port->list, &nsim_dev->port_list); 14038320d145SJiri Pirko 14048320d145SJiri Pirko return 0; 14058320d145SJiri Pirko 1406885dfe12SDmytro Linkin err_nsim_destroy: 1407885dfe12SDmytro Linkin nsim_destroy(nsim_dev_port->ns); 1408e05b2d14SJiri Pirko err_port_debugfs_exit: 1409e05b2d14SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 14108320d145SJiri Pirko err_dl_port_unregister: 141176eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14128320d145SJiri Pirko err_port_free: 14138320d145SJiri Pirko kfree(nsim_dev_port); 14148320d145SJiri Pirko return err; 14158320d145SJiri Pirko } 14168320d145SJiri Pirko 1417794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 14188320d145SJiri Pirko { 14198320d145SJiri Pirko struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 14208320d145SJiri Pirko 14218320d145SJiri Pirko list_del(&nsim_dev_port->list); 1422885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 142376eea6c2SJakub Kicinski devl_rate_leaf_destroy(&nsim_dev_port->devlink_port); 1424e05b2d14SJiri Pirko devlink_port_type_clear(devlink_port); 1425e05b2d14SJiri Pirko nsim_destroy(nsim_dev_port->ns); 14268320d145SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 142776eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14288320d145SJiri Pirko kfree(nsim_dev_port); 14298320d145SJiri Pirko } 14308320d145SJiri Pirko 14318320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 14328320d145SJiri Pirko { 14338320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port, *tmp; 14348320d145SJiri Pirko 14358320d145SJiri Pirko list_for_each_entry_safe(nsim_dev_port, tmp, 14368320d145SJiri Pirko &nsim_dev->port_list, list) 1437794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 14388320d145SJiri Pirko } 14398320d145SJiri Pirko 14407f36a77aSJiri Pirko static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, 14417f36a77aSJiri Pirko unsigned int port_count) 14428320d145SJiri Pirko { 14437f36a77aSJiri Pirko int i, err; 14448320d145SJiri Pirko 14457f36a77aSJiri Pirko for (i = 0; i < port_count; i++) { 1446814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); 14478320d145SJiri Pirko if (err) 14488320d145SJiri Pirko goto err_port_del_all; 14498320d145SJiri Pirko } 14508320d145SJiri Pirko return 0; 14518320d145SJiri Pirko 14528320d145SJiri Pirko err_port_del_all: 14538320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 14548320d145SJiri Pirko return err; 14558320d145SJiri Pirko } 14568320d145SJiri Pirko 145775ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 145875ba029fSJiri Pirko struct netlink_ext_ack *extack) 145975ba029fSJiri Pirko { 146075ba029fSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 146175ba029fSJiri Pirko struct devlink *devlink; 146275ba029fSJiri Pirko int err; 146375ba029fSJiri Pirko 146475ba029fSJiri Pirko devlink = priv_to_devlink(nsim_dev); 146575ba029fSJiri Pirko nsim_dev = devlink_priv(devlink); 146675ba029fSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 146775ba029fSJiri Pirko nsim_dev->fw_update_status = true; 1468cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 146975ba029fSJiri Pirko 147075ba029fSJiri Pirko nsim_devlink_param_load_driverinit_values(devlink); 147175ba029fSJiri Pirko 147275ba029fSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 147375ba029fSJiri Pirko if (err) 1474f57ab5b7SIdo Schimmel return err; 147575ba029fSJiri Pirko 147675ba029fSJiri Pirko err = nsim_dev_traps_init(devlink); 147775ba029fSJiri Pirko if (err) 147875ba029fSJiri Pirko goto err_dummy_region_exit; 147975ba029fSJiri Pirko 1480f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, extack); 1481f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1482f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1483f57ab5b7SIdo Schimmel goto err_traps_exit; 1484f57ab5b7SIdo Schimmel } 1485f57ab5b7SIdo Schimmel 148682c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 148775ba029fSJiri Pirko if (err) 1488f57ab5b7SIdo Schimmel goto err_fib_destroy; 148975ba029fSJiri Pirko 1490a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 149182c93a87SJiri Pirko if (err) 149282c93a87SJiri Pirko goto err_health_exit; 149382c93a87SJiri Pirko 14941a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1495a8700c3dSIdo Schimmel if (err) 1496a8700c3dSIdo Schimmel goto err_psample_exit; 1497a8700c3dSIdo Schimmel 14981a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 14991a6d7ae7SPetr Machata if (err) 15001a6d7ae7SPetr Machata goto err_hwstats_exit; 15011a6d7ae7SPetr Machata 15028526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 15038526ad96STaehee Yoo 0200, 15048526ad96STaehee Yoo nsim_dev->ddir, 15058526ad96STaehee Yoo nsim_dev, 15068526ad96STaehee Yoo &nsim_dev_take_snapshot_fops); 150775ba029fSJiri Pirko return 0; 150875ba029fSJiri Pirko 15091a6d7ae7SPetr Machata err_hwstats_exit: 15101a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1511a8700c3dSIdo Schimmel err_psample_exit: 1512a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 151382c93a87SJiri Pirko err_health_exit: 151482c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1515f57ab5b7SIdo Schimmel err_fib_destroy: 1516f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 151775ba029fSJiri Pirko err_traps_exit: 151875ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 151975ba029fSJiri Pirko err_dummy_region_exit: 152075ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 152175ba029fSJiri Pirko return err; 152275ba029fSJiri Pirko } 152375ba029fSJiri Pirko 1524a66f64b8SJakub Kicinski int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) 15257f36a77aSJiri Pirko { 15267f36a77aSJiri Pirko struct nsim_dev *nsim_dev; 15277f36a77aSJiri Pirko struct devlink *devlink; 15287f36a77aSJiri Pirko int err; 15297f36a77aSJiri Pirko 153026713455SLeon Romanovsky devlink = devlink_alloc_ns(&nsim_dev_devlink_ops, sizeof(*nsim_dev), 1531919d13a7SLeon Romanovsky nsim_bus_dev->initial_net, &nsim_bus_dev->dev); 15327f36a77aSJiri Pirko if (!devlink) 1533bfcccfe7SJakub Kicinski return -ENOMEM; 1534012ec02aSJiri Pirko devl_lock(devlink); 15357f36a77aSJiri Pirko nsim_dev = devlink_priv(devlink); 15367f36a77aSJiri Pirko nsim_dev->nsim_bus_dev = nsim_bus_dev; 15377f36a77aSJiri Pirko nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 15387f36a77aSJiri Pirko get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 15397f36a77aSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 15407f36a77aSJiri Pirko nsim_dev->fw_update_status = true; 1541cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 15427f36a77aSJiri Pirko nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; 15437f36a77aSJiri Pirko nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; 1544d3cbb907SJiri Pirko spin_lock_init(&nsim_dev->fa_cookie_lock); 15457f36a77aSJiri Pirko 1546bfcccfe7SJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 1547bfcccfe7SJakub Kicinski 15485e388f3dSJakub Kicinski nsim_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 15495e388f3dSJakub Kicinski sizeof(struct nsim_vf_config), 15505e388f3dSJakub Kicinski GFP_KERNEL | __GFP_NOWARN); 15515e388f3dSJakub Kicinski if (!nsim_dev->vfconfigs) { 15525e388f3dSJakub Kicinski err = -ENOMEM; 1553012ec02aSJiri Pirko goto err_devlink_unlock; 15545e388f3dSJakub Kicinski } 15555e388f3dSJakub Kicinski 15567f36a77aSJiri Pirko err = nsim_dev_resources_register(devlink); 15577f36a77aSJiri Pirko if (err) 15585e388f3dSJakub Kicinski goto err_vfc_free; 15597f36a77aSJiri Pirko 15607f36a77aSJiri Pirko err = devlink_params_register(devlink, nsim_devlink_params, 15617f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 15627f36a77aSJiri Pirko if (err) 15637f36a77aSJiri Pirko goto err_dl_unregister; 15647f36a77aSJiri Pirko nsim_devlink_set_params_init_values(nsim_dev, devlink); 15657f36a77aSJiri Pirko 15667f36a77aSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 15677f36a77aSJiri Pirko if (err) 15687f36a77aSJiri Pirko goto err_params_unregister; 15697f36a77aSJiri Pirko 15707f36a77aSJiri Pirko err = nsim_dev_traps_init(devlink); 15717f36a77aSJiri Pirko if (err) 15727f36a77aSJiri Pirko goto err_dummy_region_exit; 15737f36a77aSJiri Pirko 15747f36a77aSJiri Pirko err = nsim_dev_debugfs_init(nsim_dev); 15757f36a77aSJiri Pirko if (err) 15767f36a77aSJiri Pirko goto err_traps_exit; 15777f36a77aSJiri Pirko 1578f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, NULL); 1579f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1580f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1581f57ab5b7SIdo Schimmel goto err_debugfs_exit; 1582f57ab5b7SIdo Schimmel } 1583f57ab5b7SIdo Schimmel 158482c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 15857f36a77aSJiri Pirko if (err) 1586f57ab5b7SIdo Schimmel goto err_fib_destroy; 15877f36a77aSJiri Pirko 158882c93a87SJiri Pirko err = nsim_bpf_dev_init(nsim_dev); 158982c93a87SJiri Pirko if (err) 159082c93a87SJiri Pirko goto err_health_exit; 159182c93a87SJiri Pirko 1592a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 15937f36a77aSJiri Pirko if (err) 15947f36a77aSJiri Pirko goto err_bpf_dev_exit; 15957f36a77aSJiri Pirko 15961a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1597a8700c3dSIdo Schimmel if (err) 1598a8700c3dSIdo Schimmel goto err_psample_exit; 1599a8700c3dSIdo Schimmel 16001a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 16011a6d7ae7SPetr Machata if (err) 16021a6d7ae7SPetr Machata goto err_hwstats_exit; 16031a6d7ae7SPetr Machata 1604160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 1605bd032e35SLeon Romanovsky devlink_set_features(devlink, DEVLINK_F_RELOAD); 1606012ec02aSJiri Pirko devl_unlock(devlink); 160771c1b525SLeon Romanovsky devlink_register(devlink); 1608bfcccfe7SJakub Kicinski return 0; 16097f36a77aSJiri Pirko 16101a6d7ae7SPetr Machata err_hwstats_exit: 16111a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1612a8700c3dSIdo Schimmel err_psample_exit: 1613a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 16147f36a77aSJiri Pirko err_bpf_dev_exit: 16157f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 161682c93a87SJiri Pirko err_health_exit: 161782c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1618f57ab5b7SIdo Schimmel err_fib_destroy: 1619f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 16207f36a77aSJiri Pirko err_debugfs_exit: 16217f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16227f36a77aSJiri Pirko err_traps_exit: 16237f36a77aSJiri Pirko nsim_dev_traps_exit(devlink); 16247f36a77aSJiri Pirko err_dummy_region_exit: 16257f36a77aSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 16267f36a77aSJiri Pirko err_params_unregister: 16277f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16287f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 16297f36a77aSJiri Pirko err_dl_unregister: 1630012ec02aSJiri Pirko devl_resources_unregister(devlink); 16315e388f3dSJakub Kicinski err_vfc_free: 16325e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 1633012ec02aSJiri Pirko err_devlink_unlock: 1634012ec02aSJiri Pirko devl_unlock(devlink); 16357f36a77aSJiri Pirko devlink_free(devlink); 16365e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 1637bfcccfe7SJakub Kicinski return err; 16387f36a77aSJiri Pirko } 16397f36a77aSJiri Pirko 164075ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) 164175ba029fSJiri Pirko { 164275ba029fSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 164375ba029fSJiri Pirko 164475ba029fSJiri Pirko if (devlink_is_reload_failed(devlink)) 164575ba029fSJiri Pirko return; 16468526ad96STaehee Yoo debugfs_remove(nsim_dev->take_snapshot); 164732ac15d8SDmytro Linkin 16481c401078SJakub Kicinski if (nsim_dev_get_vfs(nsim_dev)) { 16491c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_dev->nsim_bus_dev, 0); 16501c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) 16511c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 16521c401078SJakub Kicinski } 165332ac15d8SDmytro Linkin 165475ba029fSJiri Pirko nsim_dev_port_del_all(nsim_dev); 16551a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1656a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 165782c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1658f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 165975ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 166075ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 166175ba029fSJiri Pirko } 166275ba029fSJiri Pirko 1663a66f64b8SJakub Kicinski void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev) 16647f36a77aSJiri Pirko { 1665bfcccfe7SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 16667f36a77aSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 16677f36a77aSJiri Pirko 166871c1b525SLeon Romanovsky devlink_unregister(devlink); 1669012ec02aSJiri Pirko devl_lock(devlink); 167075ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 167175ba029fSJiri Pirko 16727f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 16737f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16747f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16757f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 1676012ec02aSJiri Pirko devl_resources_unregister(devlink); 16775e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 1678012ec02aSJiri Pirko devl_unlock(devlink); 16797f36a77aSJiri Pirko devlink_free(devlink); 16805e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 16817f36a77aSJiri Pirko } 16827f36a77aSJiri Pirko 1683794b2c05SJiri Pirko static struct nsim_dev_port * 1684814b9ce6SDmytro Linkin __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1685814b9ce6SDmytro Linkin unsigned int port_index) 1686794b2c05SJiri Pirko { 1687794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1688794b2c05SJiri Pirko 1689814b9ce6SDmytro Linkin port_index = nsim_dev_port_index(type, port_index); 1690794b2c05SJiri Pirko list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 1691794b2c05SJiri Pirko if (nsim_dev_port->port_index == port_index) 1692794b2c05SJiri Pirko return nsim_dev_port; 1693794b2c05SJiri Pirko return NULL; 1694794b2c05SJiri Pirko } 1695794b2c05SJiri Pirko 1696a66f64b8SJakub Kicinski int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1697794b2c05SJiri Pirko unsigned int port_index) 1698794b2c05SJiri Pirko { 1699794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1700794b2c05SJiri Pirko int err; 1701794b2c05SJiri Pirko 170276eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1703814b9ce6SDmytro Linkin if (__nsim_dev_port_lookup(nsim_dev, type, port_index)) 1704794b2c05SJiri Pirko err = -EEXIST; 1705794b2c05SJiri Pirko else 1706814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, type, port_index); 170776eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1708794b2c05SJiri Pirko return err; 1709794b2c05SJiri Pirko } 1710794b2c05SJiri Pirko 1711a66f64b8SJakub Kicinski int nsim_drv_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1712794b2c05SJiri Pirko unsigned int port_index) 1713794b2c05SJiri Pirko { 1714794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1715794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1716794b2c05SJiri Pirko int err = 0; 1717794b2c05SJiri Pirko 171876eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1719814b9ce6SDmytro Linkin nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index); 1720794b2c05SJiri Pirko if (!nsim_dev_port) 1721794b2c05SJiri Pirko err = -ENOENT; 1722794b2c05SJiri Pirko else 1723794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 172476eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1725794b2c05SJiri Pirko return err; 1726794b2c05SJiri Pirko } 1727794b2c05SJiri Pirko 17281c401078SJakub Kicinski int nsim_drv_configure_vfs(struct nsim_bus_dev *nsim_bus_dev, 17291c401078SJakub Kicinski unsigned int num_vfs) 17301c401078SJakub Kicinski { 17311c401078SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1732aff3a925SJakub Kicinski struct devlink *devlink = priv_to_devlink(nsim_dev); 1733047304d0SJakub Kicinski int ret = 0; 17341c401078SJakub Kicinski 1735aff3a925SJakub Kicinski devl_lock(devlink); 1736047304d0SJakub Kicinski if (nsim_bus_dev->num_vfs == num_vfs) 17371c401078SJakub Kicinski goto exit_unlock; 17381c401078SJakub Kicinski if (nsim_bus_dev->num_vfs && num_vfs) { 17391c401078SJakub Kicinski ret = -EBUSY; 17401c401078SJakub Kicinski goto exit_unlock; 17411c401078SJakub Kicinski } 17421c401078SJakub Kicinski if (nsim_bus_dev->max_vfs < num_vfs) { 17431c401078SJakub Kicinski ret = -ENOMEM; 17441c401078SJakub Kicinski goto exit_unlock; 17451c401078SJakub Kicinski } 17461c401078SJakub Kicinski 17471c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, num_vfs); 17481c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) { 17491c401078SJakub Kicinski if (num_vfs) { 17501c401078SJakub Kicinski ret = nsim_esw_switchdev_enable(nsim_dev, NULL); 17511c401078SJakub Kicinski if (ret) { 17521c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 17531c401078SJakub Kicinski goto exit_unlock; 17541c401078SJakub Kicinski } 17551c401078SJakub Kicinski } else { 17561c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 17571c401078SJakub Kicinski } 17581c401078SJakub Kicinski } 17591c401078SJakub Kicinski 17601c401078SJakub Kicinski exit_unlock: 1761aff3a925SJakub Kicinski devl_unlock(devlink); 17621c401078SJakub Kicinski 17631c401078SJakub Kicinski return ret; 17641c401078SJakub Kicinski } 17651c401078SJakub Kicinski 1766d514f41eSJiri Pirko int nsim_dev_init(void) 1767d514f41eSJiri Pirko { 1768ab1d0cc0SJiri Pirko nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 176934611e69Skbuild test robot return PTR_ERR_OR_ZERO(nsim_dev_ddir); 1770d514f41eSJiri Pirko } 1771d514f41eSJiri Pirko 1772d514f41eSJiri Pirko void nsim_dev_exit(void) 1773d514f41eSJiri Pirko { 1774d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev_ddir); 1775d514f41eSJiri Pirko } 1776