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); 312a6aa8d0cSZhengchao Shao if (IS_ERR(nsim_dev->ports_ddir)) { 313a6aa8d0cSZhengchao Shao err = PTR_ERR(nsim_dev->ports_ddir); 314a6aa8d0cSZhengchao Shao goto err_ddir; 315a6aa8d0cSZhengchao Shao } 316fa4dfc4aSJiri Pirko debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir, 317fa4dfc4aSJiri Pirko &nsim_dev->fw_update_status); 318cbb58368SJacob Keller debugfs_create_u32("fw_update_overwrite_mask", 0600, nsim_dev->ddir, 319cbb58368SJacob Keller &nsim_dev->fw_update_overwrite_mask); 320150e8f8aSJiri Pirko debugfs_create_u32("max_macs", 0600, nsim_dev->ddir, 321150e8f8aSJiri Pirko &nsim_dev->max_macs); 322150e8f8aSJiri Pirko debugfs_create_bool("test1", 0600, nsim_dev->ddir, 323150e8f8aSJiri Pirko &nsim_dev->test1); 3248526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 3258526ad96STaehee Yoo 0200, 3268526ad96STaehee Yoo nsim_dev->ddir, 3278526ad96STaehee Yoo nsim_dev, 3284418f862SJiri Pirko &nsim_dev_take_snapshot_fops); 329155ddfc5SJiri Pirko debugfs_create_bool("dont_allow_reload", 0600, nsim_dev->ddir, 330155ddfc5SJiri Pirko &nsim_dev->dont_allow_reload); 331155ddfc5SJiri Pirko debugfs_create_bool("fail_reload", 0600, nsim_dev->ddir, 332155ddfc5SJiri Pirko &nsim_dev->fail_reload); 333d3cbb907SJiri Pirko debugfs_create_file("trap_flow_action_cookie", 0600, nsim_dev->ddir, 334d3cbb907SJiri Pirko nsim_dev, &nsim_dev_trap_fa_cookie_fops); 3350dc8249aSIdo Schimmel debugfs_create_bool("fail_trap_group_set", 0600, 3360dc8249aSIdo Schimmel nsim_dev->ddir, 3370dc8249aSIdo Schimmel &nsim_dev->fail_trap_group_set); 338ad188458SIdo Schimmel debugfs_create_bool("fail_trap_policer_set", 0600, 339ad188458SIdo Schimmel nsim_dev->ddir, 340ad188458SIdo Schimmel &nsim_dev->fail_trap_policer_set); 341ad188458SIdo Schimmel debugfs_create_bool("fail_trap_policer_counter_get", 0600, 342ad188458SIdo Schimmel nsim_dev->ddir, 343ad188458SIdo Schimmel &nsim_dev->fail_trap_policer_counter_get); 344aff3a925SJakub Kicinski /* caution, dev_max_vfs write takes devlink lock */ 345ba064e4cSJakub Kicinski debugfs_create_file("max_vfs", 0600, nsim_dev->ddir, 3465e388f3dSJakub Kicinski nsim_dev, &nsim_dev_max_vfs_fops); 347ba064e4cSJakub Kicinski 348885226f5SDmytro Linkin nsim_dev->nodes_ddir = debugfs_create_dir("rate_nodes", nsim_dev->ddir); 349f3d101b4SDmytro Linkin if (IS_ERR(nsim_dev->nodes_ddir)) { 350f3d101b4SDmytro Linkin err = PTR_ERR(nsim_dev->nodes_ddir); 351a6aa8d0cSZhengchao Shao goto err_ports_ddir; 352f3d101b4SDmytro Linkin } 353275b51c2SOleksandr Mazur debugfs_create_bool("fail_trap_drop_counter_get", 0600, 354a7b3527aSOleksandr Mazur nsim_dev->ddir, 355275b51c2SOleksandr Mazur &nsim_dev->fail_trap_drop_counter_get); 356424be63aSJakub Kicinski nsim_udp_tunnels_debugfs_create(nsim_dev); 357d514f41eSJiri Pirko return 0; 358f3d101b4SDmytro Linkin 359a6aa8d0cSZhengchao Shao err_ports_ddir: 360f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ports_ddir); 361a6aa8d0cSZhengchao Shao err_ddir: 362f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ddir); 363f3d101b4SDmytro Linkin return err; 364d514f41eSJiri Pirko } 365d514f41eSJiri Pirko 366d514f41eSJiri Pirko static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev) 367d514f41eSJiri Pirko { 368885226f5SDmytro Linkin debugfs_remove_recursive(nsim_dev->nodes_ddir); 369ab1d0cc0SJiri Pirko debugfs_remove_recursive(nsim_dev->ports_ddir); 370d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev->ddir); 371d514f41eSJiri Pirko } 372d514f41eSJiri Pirko 373f3d101b4SDmytro Linkin static ssize_t nsim_dev_rate_parent_read(struct file *file, 374f3d101b4SDmytro Linkin char __user *data, 375f3d101b4SDmytro Linkin size_t count, loff_t *ppos) 376f3d101b4SDmytro Linkin { 377f3d101b4SDmytro Linkin char **name_ptr = file->private_data; 378f3d101b4SDmytro Linkin size_t len; 379f3d101b4SDmytro Linkin 380f3d101b4SDmytro Linkin if (!*name_ptr) 381f3d101b4SDmytro Linkin return 0; 382f3d101b4SDmytro Linkin 383f3d101b4SDmytro Linkin len = strlen(*name_ptr); 384f3d101b4SDmytro Linkin return simple_read_from_buffer(data, count, ppos, *name_ptr, len); 385f3d101b4SDmytro Linkin } 386f3d101b4SDmytro Linkin 387f3d101b4SDmytro Linkin static const struct file_operations nsim_dev_rate_parent_fops = { 388f3d101b4SDmytro Linkin .open = simple_open, 389f3d101b4SDmytro Linkin .read = nsim_dev_rate_parent_read, 390f3d101b4SDmytro Linkin .llseek = generic_file_llseek, 391f3d101b4SDmytro Linkin .owner = THIS_MODULE, 392f3d101b4SDmytro Linkin }; 393f3d101b4SDmytro Linkin 3948320d145SJiri Pirko static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev, 3958320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port) 3968320d145SJiri Pirko { 397605c4f8fSDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 398605c4f8fSDmytro Linkin unsigned int port_index = nsim_dev_port->port_index; 3998320d145SJiri Pirko char port_ddir_name[16]; 4008320d145SJiri Pirko char dev_link_name[32]; 4018320d145SJiri Pirko 402605c4f8fSDmytro Linkin sprintf(port_ddir_name, "%u", port_index); 4038320d145SJiri Pirko nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name, 4048320d145SJiri Pirko nsim_dev->ports_ddir); 4056556ff32STaehee Yoo if (IS_ERR(nsim_dev_port->ddir)) 4066556ff32STaehee Yoo return PTR_ERR(nsim_dev_port->ddir); 4078320d145SJiri Pirko 408605c4f8fSDmytro Linkin sprintf(dev_link_name, "../../../" DRV_NAME "%u", nsim_bus_dev->dev.id); 409605c4f8fSDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 410605c4f8fSDmytro Linkin unsigned int vf_id = nsim_dev_port_index_to_vf_index(port_index); 411605c4f8fSDmytro Linkin 412605c4f8fSDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_dev_port->ddir, 4135e388f3dSJakub Kicinski &nsim_dev->vfconfigs[vf_id].min_tx_rate); 414605c4f8fSDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_dev_port->ddir, 4155e388f3dSJakub Kicinski &nsim_dev->vfconfigs[vf_id].max_tx_rate); 416f3d101b4SDmytro Linkin nsim_dev_port->rate_parent = debugfs_create_file("rate_parent", 417f3d101b4SDmytro Linkin 0400, 418f3d101b4SDmytro Linkin nsim_dev_port->ddir, 419f3d101b4SDmytro Linkin &nsim_dev_port->parent_name, 420f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 421605c4f8fSDmytro Linkin } 4228320d145SJiri Pirko debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name); 4238320d145SJiri Pirko 4248320d145SJiri Pirko return 0; 4258320d145SJiri Pirko } 4268320d145SJiri Pirko 4278320d145SJiri Pirko static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port) 4288320d145SJiri Pirko { 4298320d145SJiri Pirko debugfs_remove_recursive(nsim_dev_port->ddir); 4308320d145SJiri Pirko } 4318320d145SJiri Pirko 4328fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink) 4338fb4bc6fSJiri Pirko { 4348fb4bc6fSJiri Pirko struct devlink_resource_size_params params = { 4358fb4bc6fSJiri Pirko .size_max = (u64)-1, 4368fb4bc6fSJiri Pirko .size_granularity = 1, 4378fb4bc6fSJiri Pirko .unit = DEVLINK_RESOURCE_UNIT_ENTRY 4388fb4bc6fSJiri Pirko }; 4398fb4bc6fSJiri Pirko int err; 4408fb4bc6fSJiri Pirko 4418fb4bc6fSJiri Pirko /* Resources for IPv4 */ 442012ec02aSJiri Pirko err = devl_resource_register(devlink, "IPv4", (u64)-1, 4438fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, 4448fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 4458fb4bc6fSJiri Pirko ¶ms); 4468fb4bc6fSJiri Pirko if (err) { 4478fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 top resource\n"); 4486b1da9f7SZhengchao Shao goto err_out; 4498fb4bc6fSJiri Pirko } 4508fb4bc6fSJiri Pirko 451012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib", (u64)-1, 4528fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 4538fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 4548fb4bc6fSJiri Pirko if (err) { 4558fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB resource\n"); 4566b1da9f7SZhengchao Shao goto err_out; 4578fb4bc6fSJiri Pirko } 4588fb4bc6fSJiri Pirko 459012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib-rules", (u64)-1, 4608fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 4618fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 4628fb4bc6fSJiri Pirko if (err) { 4638fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB rules resource\n"); 4646b1da9f7SZhengchao Shao goto err_out; 4658fb4bc6fSJiri Pirko } 4668fb4bc6fSJiri Pirko 4678fb4bc6fSJiri Pirko /* Resources for IPv6 */ 468012ec02aSJiri Pirko err = devl_resource_register(devlink, "IPv6", (u64)-1, 4698fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, 4708fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 4718fb4bc6fSJiri Pirko ¶ms); 4728fb4bc6fSJiri Pirko if (err) { 4738fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 top resource\n"); 4746b1da9f7SZhengchao Shao goto err_out; 4758fb4bc6fSJiri Pirko } 4768fb4bc6fSJiri Pirko 477012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib", (u64)-1, 4788fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 4798fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 4808fb4bc6fSJiri Pirko if (err) { 4818fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB resource\n"); 4826b1da9f7SZhengchao Shao goto err_out; 4838fb4bc6fSJiri Pirko } 4848fb4bc6fSJiri Pirko 485012ec02aSJiri Pirko err = devl_resource_register(devlink, "fib-rules", (u64)-1, 4868fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 4878fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 4888fb4bc6fSJiri Pirko if (err) { 4898fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB rules resource\n"); 4906b1da9f7SZhengchao Shao goto err_out; 4918fb4bc6fSJiri Pirko } 4928fb4bc6fSJiri Pirko 49335266255SIdo Schimmel /* Resources for nexthops */ 494012ec02aSJiri Pirko err = devl_resource_register(devlink, "nexthops", (u64)-1, 49535266255SIdo Schimmel NSIM_RESOURCE_NEXTHOPS, 49635266255SIdo Schimmel DEVLINK_RESOURCE_ID_PARENT_TOP, 49735266255SIdo Schimmel ¶ms); 4986b1da9f7SZhengchao Shao if (err) { 4996b1da9f7SZhengchao Shao pr_err("Failed to register NEXTHOPS resource\n"); 5006b1da9f7SZhengchao Shao goto err_out; 5016b1da9f7SZhengchao Shao } 5026b1da9f7SZhengchao Shao return 0; 50335266255SIdo Schimmel 5046b1da9f7SZhengchao Shao err_out: 5056b1da9f7SZhengchao Shao devl_resources_unregister(devlink); 5068fb4bc6fSJiri Pirko return err; 5078fb4bc6fSJiri Pirko } 5088fb4bc6fSJiri Pirko 509150e8f8aSJiri Pirko enum nsim_devlink_param_id { 510150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 511150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 512150e8f8aSJiri Pirko }; 513150e8f8aSJiri Pirko 514150e8f8aSJiri Pirko static const struct devlink_param nsim_devlink_params[] = { 515150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC(MAX_MACS, 516150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 517150e8f8aSJiri Pirko NULL, NULL, NULL), 518150e8f8aSJiri Pirko DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1, 519150e8f8aSJiri Pirko "test1", DEVLINK_PARAM_TYPE_BOOL, 520150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 521150e8f8aSJiri Pirko NULL, NULL, NULL), 522150e8f8aSJiri Pirko }; 523150e8f8aSJiri Pirko 524150e8f8aSJiri Pirko static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev, 525150e8f8aSJiri Pirko struct devlink *devlink) 526150e8f8aSJiri Pirko { 527150e8f8aSJiri Pirko union devlink_param_value value; 528150e8f8aSJiri Pirko 529150e8f8aSJiri Pirko value.vu32 = nsim_dev->max_macs; 530150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 531150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 532150e8f8aSJiri Pirko value); 533150e8f8aSJiri Pirko value.vbool = nsim_dev->test1; 534150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 535150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 536150e8f8aSJiri Pirko value); 537150e8f8aSJiri Pirko } 538150e8f8aSJiri Pirko 539150e8f8aSJiri Pirko static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink) 540150e8f8aSJiri Pirko { 541150e8f8aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 542150e8f8aSJiri Pirko union devlink_param_value saved_value; 543150e8f8aSJiri Pirko int err; 544150e8f8aSJiri Pirko 545150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 546150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 547150e8f8aSJiri Pirko &saved_value); 548150e8f8aSJiri Pirko if (!err) 549150e8f8aSJiri Pirko nsim_dev->max_macs = saved_value.vu32; 550150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 551150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 552150e8f8aSJiri Pirko &saved_value); 553150e8f8aSJiri Pirko if (!err) 554150e8f8aSJiri Pirko nsim_dev->test1 = saved_value.vbool; 555150e8f8aSJiri Pirko } 556150e8f8aSJiri Pirko 5574418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX 16 5584418f862SJiri Pirko 559e8937681SJacob Keller static const struct devlink_region_ops dummy_region_ops = { 560e8937681SJacob Keller .name = "dummy", 561a0a09f6bSJacob Keller .destructor = &kfree, 5623fe0fd53SJacob Keller .snapshot = nsim_dev_take_snapshot, 563e8937681SJacob Keller }; 564e8937681SJacob Keller 5654418f862SJiri Pirko static int nsim_dev_dummy_region_init(struct nsim_dev *nsim_dev, 5664418f862SJiri Pirko struct devlink *devlink) 5674418f862SJiri Pirko { 5684418f862SJiri Pirko nsim_dev->dummy_region = 569012ec02aSJiri Pirko devl_region_create(devlink, &dummy_region_ops, 5704418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX, 5714418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SIZE); 5724418f862SJiri Pirko return PTR_ERR_OR_ZERO(nsim_dev->dummy_region); 5734418f862SJiri Pirko } 5744418f862SJiri Pirko 5754418f862SJiri Pirko static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev) 5764418f862SJiri Pirko { 577012ec02aSJiri Pirko devl_region_destroy(nsim_dev->dummy_region); 5784418f862SJiri Pirko } 5794418f862SJiri Pirko 580aff3a925SJakub Kicinski static int 581aff3a925SJakub Kicinski __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 582aff3a925SJakub Kicinski unsigned int port_index); 583160dc373SDmytro Linkin static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port); 5841c401078SJakub Kicinski 5851c401078SJakub Kicinski static int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, 5861c401078SJakub Kicinski struct netlink_ext_ack *extack) 587160dc373SDmytro Linkin { 588885226f5SDmytro Linkin struct devlink *devlink = priv_to_devlink(nsim_dev); 589160dc373SDmytro Linkin struct nsim_dev_port *nsim_dev_port, *tmp; 590160dc373SDmytro Linkin 591aff3a925SJakub Kicinski devl_rate_nodes_destroy(devlink); 592160dc373SDmytro Linkin list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) 593160dc373SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 594160dc373SDmytro Linkin __nsim_dev_port_del(nsim_dev_port); 595160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 596160dc373SDmytro Linkin return 0; 597160dc373SDmytro Linkin } 598160dc373SDmytro Linkin 5991c401078SJakub Kicinski static int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev, 6001c401078SJakub Kicinski struct netlink_ext_ack *extack) 601160dc373SDmytro Linkin { 602aff3a925SJakub Kicinski struct nsim_dev_port *nsim_dev_port, *tmp; 603160dc373SDmytro Linkin int i, err; 604160dc373SDmytro Linkin 6055e388f3dSJakub Kicinski for (i = 0; i < nsim_dev_get_vfs(nsim_dev); i++) { 606aff3a925SJakub Kicinski err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_VF, i); 607160dc373SDmytro Linkin if (err) { 608160dc373SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports"); 609160dc373SDmytro Linkin pr_err("Failed to initialize VF id=%d. %d.\n", i, err); 610160dc373SDmytro Linkin goto err_port_add_vfs; 611160dc373SDmytro Linkin } 612160dc373SDmytro Linkin } 613160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 614160dc373SDmytro Linkin return 0; 615160dc373SDmytro Linkin 616160dc373SDmytro Linkin err_port_add_vfs: 617aff3a925SJakub Kicinski list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) 618aff3a925SJakub Kicinski if (nsim_dev_port_is_vf(nsim_dev_port)) 619aff3a925SJakub Kicinski __nsim_dev_port_del(nsim_dev_port); 620160dc373SDmytro Linkin return err; 621160dc373SDmytro Linkin } 622160dc373SDmytro Linkin 623160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, 624160dc373SDmytro Linkin struct netlink_ext_ack *extack) 625160dc373SDmytro Linkin { 626160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 627160dc373SDmytro Linkin 628160dc373SDmytro Linkin if (mode == nsim_dev->esw_mode) 62914e426bfSJakub Kicinski return 0; 630160dc373SDmytro Linkin 631160dc373SDmytro Linkin if (mode == DEVLINK_ESWITCH_MODE_LEGACY) 63214e426bfSJakub Kicinski return nsim_esw_legacy_enable(nsim_dev, extack); 63314e426bfSJakub Kicinski if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) 63414e426bfSJakub Kicinski return nsim_esw_switchdev_enable(nsim_dev, extack); 635160dc373SDmytro Linkin 63614e426bfSJakub Kicinski return -EINVAL; 637160dc373SDmytro Linkin } 638160dc373SDmytro Linkin 639160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) 640160dc373SDmytro Linkin { 641160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 642160dc373SDmytro Linkin 643160dc373SDmytro Linkin *mode = nsim_dev->esw_mode; 644160dc373SDmytro Linkin return 0; 645160dc373SDmytro Linkin } 646160dc373SDmytro Linkin 647da58f90fSIdo Schimmel struct nsim_trap_item { 648da58f90fSIdo Schimmel void *trap_ctx; 649da58f90fSIdo Schimmel enum devlink_trap_action action; 650da58f90fSIdo Schimmel }; 651da58f90fSIdo Schimmel 652da58f90fSIdo Schimmel struct nsim_trap_data { 653da58f90fSIdo Schimmel struct delayed_work trap_report_dw; 654da58f90fSIdo Schimmel struct nsim_trap_item *trap_items_arr; 655ad188458SIdo Schimmel u64 *trap_policers_cnt_arr; 656a7b3527aSOleksandr Mazur u64 trap_pkt_cnt; 657da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 658da58f90fSIdo Schimmel spinlock_t trap_lock; /* Protects trap_items_arr */ 659da58f90fSIdo Schimmel }; 660da58f90fSIdo Schimmel 6619e087457SIdo Schimmel /* All driver-specific traps must be documented in 66204e4272cSJacob Keller * Documentation/networking/devlink/netdevsim.rst 6639e087457SIdo Schimmel */ 664da58f90fSIdo Schimmel enum { 665da58f90fSIdo Schimmel NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX, 666da58f90fSIdo Schimmel NSIM_TRAP_ID_FID_MISS, 667da58f90fSIdo Schimmel }; 668da58f90fSIdo Schimmel 669da58f90fSIdo Schimmel #define NSIM_TRAP_NAME_FID_MISS "fid_miss" 670da58f90fSIdo Schimmel 671da58f90fSIdo Schimmel #define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT 672da58f90fSIdo Schimmel 673da58f90fSIdo Schimmel #define NSIM_TRAP_DROP(_id, _group_id) \ 674da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 675107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 676da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 677d3cbb907SJiri Pirko #define NSIM_TRAP_DROP_EXT(_id, _group_id, _metadata) \ 678d3cbb907SJiri Pirko DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 679107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 680d3cbb907SJiri Pirko NSIM_TRAP_METADATA | (_metadata)) 681da58f90fSIdo Schimmel #define NSIM_TRAP_EXCEPTION(_id, _group_id) \ 682da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ 683107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 684da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 68518979367SIdo Schimmel #define NSIM_TRAP_CONTROL(_id, _group_id, _action) \ 68618979367SIdo Schimmel DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ 68718979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 68818979367SIdo Schimmel NSIM_TRAP_METADATA) 689da58f90fSIdo Schimmel #define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id) \ 690da58f90fSIdo Schimmel DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id, \ 691da58f90fSIdo Schimmel NSIM_TRAP_NAME_##_id, \ 692107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 693da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 694da58f90fSIdo Schimmel 695ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_RATE 1 696ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_RATE 8000 697ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_BURST 8 698ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_BURST 65536 699ad188458SIdo Schimmel 700ad188458SIdo Schimmel #define NSIM_TRAP_POLICER(_id, _rate, _burst) \ 701ad188458SIdo Schimmel DEVLINK_TRAP_POLICER(_id, _rate, _burst, \ 702ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_RATE, \ 703ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_RATE, \ 704ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_BURST, \ 705ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_BURST) 706ad188458SIdo Schimmel 707ad188458SIdo Schimmel static const struct devlink_trap_policer nsim_trap_policers_arr[] = { 708ad188458SIdo Schimmel NSIM_TRAP_POLICER(1, 1000, 128), 709ad188458SIdo Schimmel NSIM_TRAP_POLICER(2, 2000, 256), 710ad188458SIdo Schimmel NSIM_TRAP_POLICER(3, 3000, 512), 711ad188458SIdo Schimmel }; 712ad188458SIdo Schimmel 713b29545d8SIdo Schimmel static const struct devlink_trap_group nsim_trap_groups_arr[] = { 714f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), 715f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), 71685176f19SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), 717f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 2), 718f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 3), 71918979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 3), 720b29545d8SIdo Schimmel }; 721b29545d8SIdo Schimmel 722da58f90fSIdo Schimmel static const struct devlink_trap nsim_traps_arr[] = { 723da58f90fSIdo Schimmel NSIM_TRAP_DROP(SMAC_MC, L2_DROPS), 724da58f90fSIdo Schimmel NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 725da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 726da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 727da58f90fSIdo Schimmel NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 728da58f90fSIdo Schimmel NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 729da58f90fSIdo Schimmel NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS), 730da58f90fSIdo Schimmel NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 73185176f19SIdo Schimmel NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), 732da58f90fSIdo Schimmel NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS), 733d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, 734d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 735d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, 736d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 73718979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 73818979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, TRAP), 739da58f90fSIdo Schimmel }; 740da58f90fSIdo Schimmel 741da58f90fSIdo Schimmel #define NSIM_TRAP_L4_DATA_LEN 100 742da58f90fSIdo Schimmel 743da58f90fSIdo Schimmel static struct sk_buff *nsim_dev_trap_skb_build(void) 744da58f90fSIdo Schimmel { 745da58f90fSIdo Schimmel int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN; 746da58f90fSIdo Schimmel struct sk_buff *skb; 747da58f90fSIdo Schimmel struct udphdr *udph; 748da58f90fSIdo Schimmel struct ethhdr *eth; 749da58f90fSIdo Schimmel struct iphdr *iph; 750da58f90fSIdo Schimmel 751da58f90fSIdo Schimmel skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 752da58f90fSIdo Schimmel if (!skb) 753da58f90fSIdo Schimmel return NULL; 754da58f90fSIdo Schimmel tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len; 755da58f90fSIdo Schimmel 75658a406deSIdo Schimmel skb_reset_mac_header(skb); 757da58f90fSIdo Schimmel eth = skb_put(skb, sizeof(struct ethhdr)); 758da58f90fSIdo Schimmel eth_random_addr(eth->h_dest); 759da58f90fSIdo Schimmel eth_random_addr(eth->h_source); 760da58f90fSIdo Schimmel eth->h_proto = htons(ETH_P_IP); 761da58f90fSIdo Schimmel skb->protocol = htons(ETH_P_IP); 762da58f90fSIdo Schimmel 76358a406deSIdo Schimmel skb_set_network_header(skb, skb->len); 764da58f90fSIdo Schimmel iph = skb_put(skb, sizeof(struct iphdr)); 765da58f90fSIdo Schimmel iph->protocol = IPPROTO_UDP; 766da58f90fSIdo Schimmel iph->saddr = in_aton("192.0.2.1"); 767da58f90fSIdo Schimmel iph->daddr = in_aton("198.51.100.1"); 768da58f90fSIdo Schimmel iph->version = 0x4; 769da58f90fSIdo Schimmel iph->frag_off = 0; 770da58f90fSIdo Schimmel iph->ihl = 0x5; 771da58f90fSIdo Schimmel iph->tot_len = htons(tot_len); 772da58f90fSIdo Schimmel iph->ttl = 100; 773d9bd6d27SYueHaibing iph->check = 0; 774d9bd6d27SYueHaibing iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 775da58f90fSIdo Schimmel 77658a406deSIdo Schimmel skb_set_transport_header(skb, skb->len); 777da58f90fSIdo Schimmel udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len); 778da58f90fSIdo Schimmel get_random_bytes(&udph->source, sizeof(u16)); 779da58f90fSIdo Schimmel get_random_bytes(&udph->dest, sizeof(u16)); 780da58f90fSIdo Schimmel udph->len = htons(sizeof(struct udphdr) + data_len); 781da58f90fSIdo Schimmel 782da58f90fSIdo Schimmel return skb; 783da58f90fSIdo Schimmel } 784da58f90fSIdo Schimmel 785da58f90fSIdo Schimmel static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port) 786da58f90fSIdo Schimmel { 787da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 788da58f90fSIdo Schimmel struct devlink *devlink = priv_to_devlink(nsim_dev); 789da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 790da58f90fSIdo Schimmel int i; 791da58f90fSIdo Schimmel 792da58f90fSIdo Schimmel nsim_trap_data = nsim_dev->trap_data; 793da58f90fSIdo Schimmel 794da58f90fSIdo Schimmel spin_lock(&nsim_trap_data->trap_lock); 795da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 796d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie = NULL; 797da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 798da58f90fSIdo Schimmel struct sk_buff *skb; 799d3cbb907SJiri Pirko bool has_fa_cookie; 800d3cbb907SJiri Pirko 801d3cbb907SJiri Pirko has_fa_cookie = nsim_traps_arr[i].metadata_cap & 802d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE; 803da58f90fSIdo Schimmel 804da58f90fSIdo Schimmel nsim_trap_item = &nsim_trap_data->trap_items_arr[i]; 805da58f90fSIdo Schimmel if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP) 806da58f90fSIdo Schimmel continue; 807da58f90fSIdo Schimmel 808da58f90fSIdo Schimmel skb = nsim_dev_trap_skb_build(); 809da58f90fSIdo Schimmel if (!skb) 810da58f90fSIdo Schimmel continue; 811da58f90fSIdo Schimmel skb->dev = nsim_dev_port->ns->netdev; 812da58f90fSIdo Schimmel 813da58f90fSIdo Schimmel /* Trapped packets are usually passed to devlink in softIRQ, 814da58f90fSIdo Schimmel * but in this case they are generated in a workqueue. Disable 815da58f90fSIdo Schimmel * softIRQs to prevent lockdep from complaining about 816da58f90fSIdo Schimmel * "incosistent lock state". 817da58f90fSIdo Schimmel */ 818d3cbb907SJiri Pirko 819d3cbb907SJiri Pirko spin_lock_bh(&nsim_dev->fa_cookie_lock); 820d3cbb907SJiri Pirko fa_cookie = has_fa_cookie ? nsim_dev->fa_cookie : NULL; 821da58f90fSIdo Schimmel devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx, 822d3cbb907SJiri Pirko &nsim_dev_port->devlink_port, fa_cookie); 823d3cbb907SJiri Pirko spin_unlock_bh(&nsim_dev->fa_cookie_lock); 824da58f90fSIdo Schimmel consume_skb(skb); 825da58f90fSIdo Schimmel } 826da58f90fSIdo Schimmel spin_unlock(&nsim_trap_data->trap_lock); 827da58f90fSIdo Schimmel } 828da58f90fSIdo Schimmel 829da58f90fSIdo Schimmel #define NSIM_TRAP_REPORT_INTERVAL_MS 100 830da58f90fSIdo Schimmel 831da58f90fSIdo Schimmel static void nsim_dev_trap_report_work(struct work_struct *work) 832da58f90fSIdo Schimmel { 833da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 834da58f90fSIdo Schimmel struct nsim_dev_port *nsim_dev_port; 835da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 836da58f90fSIdo Schimmel 837da58f90fSIdo Schimmel nsim_trap_data = container_of(work, struct nsim_trap_data, 838da58f90fSIdo Schimmel trap_report_dw.work); 839da58f90fSIdo Schimmel nsim_dev = nsim_trap_data->nsim_dev; 840da58f90fSIdo Schimmel 841da58f90fSIdo Schimmel /* For each running port and enabled packet trap, generate a UDP 842da58f90fSIdo Schimmel * packet with a random 5-tuple and report it. 843da58f90fSIdo Schimmel */ 844012ec02aSJiri Pirko if (!devl_trylock(priv_to_devlink(nsim_dev))) { 845012ec02aSJiri Pirko schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 0); 846012ec02aSJiri Pirko return; 847012ec02aSJiri Pirko } 848012ec02aSJiri Pirko 849da58f90fSIdo Schimmel list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) { 850da58f90fSIdo Schimmel if (!netif_running(nsim_dev_port->ns->netdev)) 851da58f90fSIdo Schimmel continue; 852da58f90fSIdo Schimmel 853da58f90fSIdo Schimmel nsim_dev_trap_report(nsim_dev_port); 854da58f90fSIdo Schimmel } 85576eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 856da58f90fSIdo Schimmel 857da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 858da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 859da58f90fSIdo Schimmel } 860da58f90fSIdo Schimmel 861da58f90fSIdo Schimmel static int nsim_dev_traps_init(struct devlink *devlink) 862da58f90fSIdo Schimmel { 863ad188458SIdo Schimmel size_t policers_count = ARRAY_SIZE(nsim_trap_policers_arr); 864da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 865da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 866da58f90fSIdo Schimmel int err; 867da58f90fSIdo Schimmel 868da58f90fSIdo Schimmel nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL); 869da58f90fSIdo Schimmel if (!nsim_trap_data) 870da58f90fSIdo Schimmel return -ENOMEM; 871da58f90fSIdo Schimmel 872da58f90fSIdo Schimmel nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr), 873da58f90fSIdo Schimmel sizeof(struct nsim_trap_item), 874da58f90fSIdo Schimmel GFP_KERNEL); 875da58f90fSIdo Schimmel if (!nsim_trap_data->trap_items_arr) { 876da58f90fSIdo Schimmel err = -ENOMEM; 877da58f90fSIdo Schimmel goto err_trap_data_free; 878da58f90fSIdo Schimmel } 879da58f90fSIdo Schimmel 880ad188458SIdo Schimmel nsim_trap_data->trap_policers_cnt_arr = kcalloc(policers_count, 881ad188458SIdo Schimmel sizeof(u64), 882ad188458SIdo Schimmel GFP_KERNEL); 883ad188458SIdo Schimmel if (!nsim_trap_data->trap_policers_cnt_arr) { 884ad188458SIdo Schimmel err = -ENOMEM; 885ad188458SIdo Schimmel goto err_trap_items_free; 886ad188458SIdo Schimmel } 887ad188458SIdo Schimmel 888da58f90fSIdo Schimmel /* The lock is used to protect the action state of the registered 889da58f90fSIdo Schimmel * traps. The value is written by user and read in delayed work when 890da58f90fSIdo Schimmel * iterating over all the traps. 891da58f90fSIdo Schimmel */ 892da58f90fSIdo Schimmel spin_lock_init(&nsim_trap_data->trap_lock); 893da58f90fSIdo Schimmel nsim_trap_data->nsim_dev = nsim_dev; 894da58f90fSIdo Schimmel nsim_dev->trap_data = nsim_trap_data; 895da58f90fSIdo Schimmel 896012ec02aSJiri Pirko err = devl_trap_policers_register(devlink, nsim_trap_policers_arr, 897ad188458SIdo Schimmel policers_count); 898ad188458SIdo Schimmel if (err) 899ad188458SIdo Schimmel goto err_trap_policers_cnt_free; 900ad188458SIdo Schimmel 901012ec02aSJiri Pirko err = devl_trap_groups_register(devlink, nsim_trap_groups_arr, 902b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 903b29545d8SIdo Schimmel if (err) 904ad188458SIdo Schimmel goto err_trap_policers_unregister; 905b29545d8SIdo Schimmel 906012ec02aSJiri Pirko err = devl_traps_register(devlink, nsim_traps_arr, 907da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr), NULL); 908da58f90fSIdo Schimmel if (err) 909b29545d8SIdo Schimmel goto err_trap_groups_unregister; 910da58f90fSIdo Schimmel 911da58f90fSIdo Schimmel INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw, 912da58f90fSIdo Schimmel nsim_dev_trap_report_work); 913da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 914da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 915da58f90fSIdo Schimmel 916da58f90fSIdo Schimmel return 0; 917da58f90fSIdo Schimmel 918b29545d8SIdo Schimmel err_trap_groups_unregister: 919012ec02aSJiri Pirko devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, 920b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 921ad188458SIdo Schimmel err_trap_policers_unregister: 922012ec02aSJiri Pirko devl_trap_policers_unregister(devlink, nsim_trap_policers_arr, 923ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 924ad188458SIdo Schimmel err_trap_policers_cnt_free: 925ad188458SIdo Schimmel kfree(nsim_trap_data->trap_policers_cnt_arr); 926da58f90fSIdo Schimmel err_trap_items_free: 927da58f90fSIdo Schimmel kfree(nsim_trap_data->trap_items_arr); 928da58f90fSIdo Schimmel err_trap_data_free: 929da58f90fSIdo Schimmel kfree(nsim_trap_data); 930da58f90fSIdo Schimmel return err; 931da58f90fSIdo Schimmel } 932da58f90fSIdo Schimmel 933da58f90fSIdo Schimmel static void nsim_dev_traps_exit(struct devlink *devlink) 934da58f90fSIdo Schimmel { 935da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 936da58f90fSIdo Schimmel 93776eea6c2SJakub Kicinski /* caution, trap work takes devlink lock */ 938da58f90fSIdo Schimmel cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw); 939012ec02aSJiri Pirko devl_traps_unregister(devlink, nsim_traps_arr, 940da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr)); 941012ec02aSJiri Pirko devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, 942b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 943012ec02aSJiri Pirko devl_trap_policers_unregister(devlink, nsim_trap_policers_arr, 944ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 945ad188458SIdo Schimmel kfree(nsim_dev->trap_data->trap_policers_cnt_arr); 946da58f90fSIdo Schimmel kfree(nsim_dev->trap_data->trap_items_arr); 947da58f90fSIdo Schimmel kfree(nsim_dev->trap_data); 948da58f90fSIdo Schimmel } 949da58f90fSIdo Schimmel 95075ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 95175ba029fSJiri Pirko struct netlink_ext_ack *extack); 95275ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); 95375ba029fSJiri Pirko 954070c63f2SJiri Pirko static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, 955dc64cc7cSMoshe Shemesh enum devlink_reload_action action, enum devlink_reload_limit limit, 956dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 95797691069SJiri Pirko { 95875ba029fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 95923809a72SLeon Romanovsky 960155ddfc5SJiri Pirko if (nsim_dev->dont_allow_reload) { 961155ddfc5SJiri Pirko /* For testing purposes, user set debugfs dont_allow_reload 962155ddfc5SJiri Pirko * value to true. So forbid it. 963155ddfc5SJiri Pirko */ 964f9867b51SColin Ian King NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); 965155ddfc5SJiri Pirko return -EOPNOTSUPP; 966155ddfc5SJiri Pirko } 967155ddfc5SJiri Pirko 96875ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 96997691069SJiri Pirko return 0; 97097691069SJiri Pirko } 97197691069SJiri Pirko 972ccdf0721SMoshe Shemesh static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action, 973dc64cc7cSMoshe Shemesh enum devlink_reload_limit limit, u32 *actions_performed, 974dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 9758fb4bc6fSJiri Pirko { 976a5facc4cSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 9775c0418edSLeon Romanovsky 978155ddfc5SJiri Pirko if (nsim_dev->fail_reload) { 979155ddfc5SJiri Pirko /* For testing purposes, user set debugfs fail_reload 980155ddfc5SJiri Pirko * value to true. Fail right away. 981155ddfc5SJiri Pirko */ 982155ddfc5SJiri Pirko NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); 983155ddfc5SJiri Pirko return -EINVAL; 984155ddfc5SJiri Pirko } 985155ddfc5SJiri Pirko 986ccdf0721SMoshe Shemesh *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 9875603072eSJinpeng Cui 9885603072eSJinpeng Cui return nsim_dev_reload_create(nsim_dev, extack); 9898fb4bc6fSJiri Pirko } 9908fb4bc6fSJiri Pirko 9918e23cc03SJiri Pirko static int nsim_dev_info_get(struct devlink *devlink, 9928e23cc03SJiri Pirko struct devlink_info_req *req, 9938e23cc03SJiri Pirko struct netlink_ext_ack *extack) 9948e23cc03SJiri Pirko { 9950c198975SJiri Pirko int err; 9960c198975SJiri Pirko 9970c198975SJiri Pirko err = devlink_info_driver_name_put(req, DRV_NAME); 9980c198975SJiri Pirko if (err) 9990c198975SJiri Pirko return err; 10000c198975SJiri Pirko err = devlink_info_version_stored_put_ext(req, "fw.mgmt", "10.20.30", 10010c198975SJiri Pirko DEVLINK_INFO_VERSION_TYPE_COMPONENT); 10020c198975SJiri Pirko if (err) 10030c198975SJiri Pirko return err; 10040c198975SJiri Pirko return devlink_info_version_running_put_ext(req, "fw.mgmt", "10.20.30", 10050c198975SJiri Pirko DEVLINK_INFO_VERSION_TYPE_COMPONENT); 10068e23cc03SJiri Pirko } 10078e23cc03SJiri Pirko 1008fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000 1009fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 1010fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 1011fa4dfc4aSJiri Pirko 1012bc75c054SJacob Keller static int nsim_dev_flash_update(struct devlink *devlink, 1013bc75c054SJacob Keller struct devlink_flash_update_params *params, 1014fa4dfc4aSJiri Pirko struct netlink_ext_ack *extack) 1015fa4dfc4aSJiri Pirko { 1016fa4dfc4aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 1017fa4dfc4aSJiri Pirko int i; 1018fa4dfc4aSJiri Pirko 1019cbb58368SJacob Keller if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0) 1020cbb58368SJacob Keller return -EOPNOTSUPP; 1021cbb58368SJacob Keller 1022fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1023fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, 1024fa4dfc4aSJiri Pirko "Preparing to flash", 1025bc75c054SJacob Keller params->component, 0, 0); 1026fa4dfc4aSJiri Pirko } 1027fa4dfc4aSJiri Pirko 1028fa4dfc4aSJiri Pirko for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 1029fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) 1030fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1031bc75c054SJacob Keller params->component, 1032fa4dfc4aSJiri Pirko i * NSIM_DEV_FLASH_CHUNK_SIZE, 1033fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1034fa4dfc4aSJiri Pirko msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 1035fa4dfc4aSJiri Pirko } 1036fa4dfc4aSJiri Pirko 1037fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1038fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1039bc75c054SJacob Keller params->component, 1040fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE, 1041fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1042b311b001SShannon Nelson devlink_flash_update_timeout_notify(devlink, "Flash select", 1043bc75c054SJacob Keller params->component, 81); 1044fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing done", 1045bc75c054SJacob Keller params->component, 0, 0); 1046fa4dfc4aSJiri Pirko } 1047fa4dfc4aSJiri Pirko 1048fa4dfc4aSJiri Pirko return 0; 1049fa4dfc4aSJiri Pirko } 1050fa4dfc4aSJiri Pirko 1051da58f90fSIdo Schimmel static struct nsim_trap_item * 1052da58f90fSIdo Schimmel nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id) 1053da58f90fSIdo Schimmel { 1054da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data; 1055da58f90fSIdo Schimmel int i; 1056da58f90fSIdo Schimmel 1057da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 1058da58f90fSIdo Schimmel if (nsim_traps_arr[i].id == trap_id) 1059da58f90fSIdo Schimmel return &nsim_trap_data->trap_items_arr[i]; 1060da58f90fSIdo Schimmel } 1061da58f90fSIdo Schimmel 1062da58f90fSIdo Schimmel return NULL; 1063da58f90fSIdo Schimmel } 1064da58f90fSIdo Schimmel 1065da58f90fSIdo Schimmel static int nsim_dev_devlink_trap_init(struct devlink *devlink, 1066da58f90fSIdo Schimmel const struct devlink_trap *trap, 1067da58f90fSIdo Schimmel void *trap_ctx) 1068da58f90fSIdo Schimmel { 1069da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1070da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1071da58f90fSIdo Schimmel 1072da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1073da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1074da58f90fSIdo Schimmel return -ENOENT; 1075da58f90fSIdo Schimmel 1076da58f90fSIdo Schimmel nsim_trap_item->trap_ctx = trap_ctx; 1077da58f90fSIdo Schimmel nsim_trap_item->action = trap->init_action; 1078da58f90fSIdo Schimmel 1079da58f90fSIdo Schimmel return 0; 1080da58f90fSIdo Schimmel } 1081da58f90fSIdo Schimmel 1082da58f90fSIdo Schimmel static int 1083da58f90fSIdo Schimmel nsim_dev_devlink_trap_action_set(struct devlink *devlink, 1084da58f90fSIdo Schimmel const struct devlink_trap *trap, 1085c88e11e0SIdo Schimmel enum devlink_trap_action action, 1086c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 1087da58f90fSIdo Schimmel { 1088da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1089da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1090da58f90fSIdo Schimmel 1091da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1092da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1093da58f90fSIdo Schimmel return -ENOENT; 1094da58f90fSIdo Schimmel 1095da58f90fSIdo Schimmel spin_lock(&nsim_dev->trap_data->trap_lock); 1096da58f90fSIdo Schimmel nsim_trap_item->action = action; 1097da58f90fSIdo Schimmel spin_unlock(&nsim_dev->trap_data->trap_lock); 1098da58f90fSIdo Schimmel 1099da58f90fSIdo Schimmel return 0; 1100da58f90fSIdo Schimmel } 1101da58f90fSIdo Schimmel 1102ad188458SIdo Schimmel static int 11030dc8249aSIdo Schimmel nsim_dev_devlink_trap_group_set(struct devlink *devlink, 11040dc8249aSIdo Schimmel const struct devlink_trap_group *group, 1105c88e11e0SIdo Schimmel const struct devlink_trap_policer *policer, 1106c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 11070dc8249aSIdo Schimmel { 11080dc8249aSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 11090dc8249aSIdo Schimmel 11100dc8249aSIdo Schimmel if (nsim_dev->fail_trap_group_set) 11110dc8249aSIdo Schimmel return -EINVAL; 11120dc8249aSIdo Schimmel 11130dc8249aSIdo Schimmel return 0; 11140dc8249aSIdo Schimmel } 11150dc8249aSIdo Schimmel 11160dc8249aSIdo Schimmel static int 1117ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_set(struct devlink *devlink, 1118ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1119ad188458SIdo Schimmel u64 rate, u64 burst, 1120ad188458SIdo Schimmel struct netlink_ext_ack *extack) 1121ad188458SIdo Schimmel { 1122ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1123ad188458SIdo Schimmel 1124ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_set) { 1125ad188458SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes"); 1126ad188458SIdo Schimmel return -EINVAL; 1127ad188458SIdo Schimmel } 1128ad188458SIdo Schimmel 1129ad188458SIdo Schimmel return 0; 1130ad188458SIdo Schimmel } 1131ad188458SIdo Schimmel 1132ad188458SIdo Schimmel static int 1133ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink, 1134ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1135ad188458SIdo Schimmel u64 *p_drops) 1136ad188458SIdo Schimmel { 1137ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1138ad188458SIdo Schimmel u64 *cnt; 1139ad188458SIdo Schimmel 1140ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_counter_get) 1141ad188458SIdo Schimmel return -EINVAL; 1142ad188458SIdo Schimmel 1143ad188458SIdo Schimmel cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1]; 1144be43224fSIdo Schimmel *p_drops = (*cnt)++; 1145ad188458SIdo Schimmel 1146ad188458SIdo Schimmel return 0; 1147ad188458SIdo Schimmel } 1148ad188458SIdo Schimmel 1149605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_MAX 5000 /* Mbps */ 1150605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_UNIT 125000 /* 1 Mbps given in bytes/sec to avoid 1151605c4f8fSDmytro Linkin * u64 overflow during conversion from 1152605c4f8fSDmytro Linkin * bytes to bits. 1153605c4f8fSDmytro Linkin */ 1154605c4f8fSDmytro Linkin 1155605c4f8fSDmytro Linkin static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack) 1156605c4f8fSDmytro Linkin { 1157605c4f8fSDmytro Linkin u64 val; 1158605c4f8fSDmytro Linkin u32 rem; 1159605c4f8fSDmytro Linkin 1160605c4f8fSDmytro Linkin val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem); 1161605c4f8fSDmytro Linkin if (rem) { 1162605c4f8fSDmytro Linkin pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n", 1163605c4f8fSDmytro Linkin name, *rate); 1164605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps."); 1165605c4f8fSDmytro Linkin return -EINVAL; 1166605c4f8fSDmytro Linkin } 1167605c4f8fSDmytro Linkin 1168605c4f8fSDmytro Linkin if (val > NSIM_LINK_SPEED_MAX) { 1169605c4f8fSDmytro Linkin pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n", 1170605c4f8fSDmytro Linkin name, val); 1171605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps."); 1172605c4f8fSDmytro Linkin return -EINVAL; 1173605c4f8fSDmytro Linkin } 1174605c4f8fSDmytro Linkin *rate = val; 1175605c4f8fSDmytro Linkin return 0; 1176605c4f8fSDmytro Linkin } 1177605c4f8fSDmytro Linkin 1178605c4f8fSDmytro Linkin static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1179605c4f8fSDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1180605c4f8fSDmytro Linkin { 1181605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11825e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1183605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1184605c4f8fSDmytro Linkin int err; 1185605c4f8fSDmytro Linkin 1186605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1187605c4f8fSDmytro Linkin if (err) 1188605c4f8fSDmytro Linkin return err; 1189605c4f8fSDmytro Linkin 11905e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].min_tx_rate = tx_share; 1191605c4f8fSDmytro Linkin return 0; 1192605c4f8fSDmytro Linkin } 1193605c4f8fSDmytro Linkin 1194605c4f8fSDmytro Linkin static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1195605c4f8fSDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1196605c4f8fSDmytro Linkin { 1197605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11985e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1199605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1200605c4f8fSDmytro Linkin int err; 1201605c4f8fSDmytro Linkin 1202605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1203605c4f8fSDmytro Linkin if (err) 1204605c4f8fSDmytro Linkin return err; 1205605c4f8fSDmytro Linkin 12065e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].max_tx_rate = tx_max; 1207605c4f8fSDmytro Linkin return 0; 1208605c4f8fSDmytro Linkin } 1209605c4f8fSDmytro Linkin 1210885226f5SDmytro Linkin struct nsim_rate_node { 1211885226f5SDmytro Linkin struct dentry *ddir; 1212f3d101b4SDmytro Linkin struct dentry *rate_parent; 1213f3d101b4SDmytro Linkin char *parent_name; 1214885226f5SDmytro Linkin u16 tx_share; 1215885226f5SDmytro Linkin u16 tx_max; 1216885226f5SDmytro Linkin }; 1217885226f5SDmytro Linkin 1218885226f5SDmytro Linkin static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1219885226f5SDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1220885226f5SDmytro Linkin { 1221885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1222885226f5SDmytro Linkin int err; 1223885226f5SDmytro Linkin 1224885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1225885226f5SDmytro Linkin if (err) 1226885226f5SDmytro Linkin return err; 1227885226f5SDmytro Linkin 1228885226f5SDmytro Linkin nsim_node->tx_share = tx_share; 1229885226f5SDmytro Linkin return 0; 1230885226f5SDmytro Linkin } 1231885226f5SDmytro Linkin 1232885226f5SDmytro Linkin static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1233885226f5SDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1234885226f5SDmytro Linkin { 1235885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1236885226f5SDmytro Linkin int err; 1237885226f5SDmytro Linkin 1238885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1239885226f5SDmytro Linkin if (err) 1240885226f5SDmytro Linkin return err; 1241885226f5SDmytro Linkin 1242885226f5SDmytro Linkin nsim_node->tx_max = tx_max; 1243885226f5SDmytro Linkin return 0; 1244885226f5SDmytro Linkin } 1245885226f5SDmytro Linkin 1246885226f5SDmytro Linkin static int nsim_rate_node_new(struct devlink_rate *node, void **priv, 1247885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1248885226f5SDmytro Linkin { 1249885226f5SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(node->devlink); 1250885226f5SDmytro Linkin struct nsim_rate_node *nsim_node; 1251885226f5SDmytro Linkin 1252885226f5SDmytro Linkin if (!nsim_esw_mode_is_switchdev(nsim_dev)) { 1253885226f5SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode."); 1254885226f5SDmytro Linkin return -EOPNOTSUPP; 1255885226f5SDmytro Linkin } 1256885226f5SDmytro Linkin 1257885226f5SDmytro Linkin nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL); 1258885226f5SDmytro Linkin if (!nsim_node) 1259885226f5SDmytro Linkin return -ENOMEM; 1260885226f5SDmytro Linkin 1261885226f5SDmytro Linkin nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir); 12624e744cb8SDan Carpenter 1263885226f5SDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share); 1264885226f5SDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max); 1265f3d101b4SDmytro Linkin nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400, 1266f3d101b4SDmytro Linkin nsim_node->ddir, 1267f3d101b4SDmytro Linkin &nsim_node->parent_name, 1268f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 1269f3d101b4SDmytro Linkin 1270885226f5SDmytro Linkin *priv = nsim_node; 1271885226f5SDmytro Linkin return 0; 1272885226f5SDmytro Linkin } 1273885226f5SDmytro Linkin 1274885226f5SDmytro Linkin static int nsim_rate_node_del(struct devlink_rate *node, void *priv, 1275885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1276885226f5SDmytro Linkin { 1277885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1278885226f5SDmytro Linkin 1279f3d101b4SDmytro Linkin debugfs_remove(nsim_node->rate_parent); 1280885226f5SDmytro Linkin debugfs_remove_recursive(nsim_node->ddir); 1281885226f5SDmytro Linkin kfree(nsim_node); 1282885226f5SDmytro Linkin return 0; 1283885226f5SDmytro Linkin } 1284885226f5SDmytro Linkin 1285f3d101b4SDmytro Linkin static int nsim_rate_leaf_parent_set(struct devlink_rate *child, 1286f3d101b4SDmytro Linkin struct devlink_rate *parent, 1287f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1288f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1289f3d101b4SDmytro Linkin { 1290f3d101b4SDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv_child; 1291f3d101b4SDmytro Linkin 1292f3d101b4SDmytro Linkin if (parent) 1293f3d101b4SDmytro Linkin nsim_dev_port->parent_name = parent->name; 1294f3d101b4SDmytro Linkin else 1295f3d101b4SDmytro Linkin nsim_dev_port->parent_name = NULL; 1296f3d101b4SDmytro Linkin return 0; 1297f3d101b4SDmytro Linkin } 1298f3d101b4SDmytro Linkin 1299f3d101b4SDmytro Linkin static int nsim_rate_node_parent_set(struct devlink_rate *child, 1300f3d101b4SDmytro Linkin struct devlink_rate *parent, 1301f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1302f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1303f3d101b4SDmytro Linkin { 1304f3d101b4SDmytro Linkin struct nsim_rate_node *nsim_node = priv_child; 1305f3d101b4SDmytro Linkin 1306f3d101b4SDmytro Linkin if (parent) 1307f3d101b4SDmytro Linkin nsim_node->parent_name = parent->name; 1308f3d101b4SDmytro Linkin else 1309f3d101b4SDmytro Linkin nsim_node->parent_name = NULL; 1310f3d101b4SDmytro Linkin return 0; 1311f3d101b4SDmytro Linkin } 1312f3d101b4SDmytro Linkin 1313a7b3527aSOleksandr Mazur static int 1314275b51c2SOleksandr Mazur nsim_dev_devlink_trap_drop_counter_get(struct devlink *devlink, 1315a7b3527aSOleksandr Mazur const struct devlink_trap *trap, 1316a7b3527aSOleksandr Mazur u64 *p_drops) 1317a7b3527aSOleksandr Mazur { 1318a7b3527aSOleksandr Mazur struct nsim_dev *nsim_dev = devlink_priv(devlink); 1319a7b3527aSOleksandr Mazur u64 *cnt; 1320a7b3527aSOleksandr Mazur 1321275b51c2SOleksandr Mazur if (nsim_dev->fail_trap_drop_counter_get) 1322a7b3527aSOleksandr Mazur return -EINVAL; 1323a7b3527aSOleksandr Mazur 1324a7b3527aSOleksandr Mazur cnt = &nsim_dev->trap_data->trap_pkt_cnt; 1325a7b3527aSOleksandr Mazur *p_drops = (*cnt)++; 1326a7b3527aSOleksandr Mazur 1327a7b3527aSOleksandr Mazur return 0; 1328a7b3527aSOleksandr Mazur } 1329a7b3527aSOleksandr Mazur 13308fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 1331160dc373SDmytro Linkin .eswitch_mode_set = nsim_devlink_eswitch_mode_set, 1332160dc373SDmytro Linkin .eswitch_mode_get = nsim_devlink_eswitch_mode_get, 1333f94b6063SJiri Pirko .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, 1334ccdf0721SMoshe Shemesh .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), 133597691069SJiri Pirko .reload_down = nsim_dev_reload_down, 133697691069SJiri Pirko .reload_up = nsim_dev_reload_up, 13378e23cc03SJiri Pirko .info_get = nsim_dev_info_get, 1338fa4dfc4aSJiri Pirko .flash_update = nsim_dev_flash_update, 1339da58f90fSIdo Schimmel .trap_init = nsim_dev_devlink_trap_init, 1340da58f90fSIdo Schimmel .trap_action_set = nsim_dev_devlink_trap_action_set, 13410dc8249aSIdo Schimmel .trap_group_set = nsim_dev_devlink_trap_group_set, 1342ad188458SIdo Schimmel .trap_policer_set = nsim_dev_devlink_trap_policer_set, 1343ad188458SIdo Schimmel .trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get, 1344605c4f8fSDmytro Linkin .rate_leaf_tx_share_set = nsim_leaf_tx_share_set, 1345605c4f8fSDmytro Linkin .rate_leaf_tx_max_set = nsim_leaf_tx_max_set, 1346885226f5SDmytro Linkin .rate_node_tx_share_set = nsim_node_tx_share_set, 1347885226f5SDmytro Linkin .rate_node_tx_max_set = nsim_node_tx_max_set, 1348885226f5SDmytro Linkin .rate_node_new = nsim_rate_node_new, 1349885226f5SDmytro Linkin .rate_node_del = nsim_rate_node_del, 1350f3d101b4SDmytro Linkin .rate_leaf_parent_set = nsim_rate_leaf_parent_set, 1351f3d101b4SDmytro Linkin .rate_node_parent_set = nsim_rate_node_parent_set, 1352275b51c2SOleksandr Mazur .trap_drop_counter_get = nsim_dev_devlink_trap_drop_counter_get, 13538fb4bc6fSJiri Pirko }; 13548fb4bc6fSJiri Pirko 1355150e8f8aSJiri Pirko #define NSIM_DEV_MAX_MACS_DEFAULT 32 1356150e8f8aSJiri Pirko #define NSIM_DEV_TEST1_DEFAULT true 1357150e8f8aSJiri Pirko 1358814b9ce6SDmytro Linkin static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1359794b2c05SJiri Pirko unsigned int port_index) 13608320d145SJiri Pirko { 136171ad8d55SDanielle Ratson struct devlink_port_attrs attrs = {}; 13628320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port; 13638320d145SJiri Pirko struct devlink_port *devlink_port; 13648320d145SJiri Pirko int err; 13658320d145SJiri Pirko 13665e388f3dSJakub Kicinski if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_dev_get_vfs(nsim_dev)) 136792ba1f29SDmytro Linkin return -EINVAL; 136892ba1f29SDmytro Linkin 13698320d145SJiri Pirko nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); 13708320d145SJiri Pirko if (!nsim_dev_port) 13718320d145SJiri Pirko return -ENOMEM; 1372814b9ce6SDmytro Linkin nsim_dev_port->port_index = nsim_dev_port_index(type, port_index); 1373814b9ce6SDmytro Linkin nsim_dev_port->port_type = type; 13748320d145SJiri Pirko 13758320d145SJiri Pirko devlink_port = &nsim_dev_port->devlink_port; 137692ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) { 137771ad8d55SDanielle Ratson attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 137871ad8d55SDanielle Ratson attrs.phys.port_number = port_index + 1; 137992ba1f29SDmytro Linkin } else { 138092ba1f29SDmytro Linkin attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; 138192ba1f29SDmytro Linkin attrs.pci_vf.pf = 0; 138292ba1f29SDmytro Linkin attrs.pci_vf.vf = port_index; 138392ba1f29SDmytro Linkin } 138471ad8d55SDanielle Ratson memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 138571ad8d55SDanielle Ratson attrs.switch_id.id_len = nsim_dev->switch_id.id_len; 138671ad8d55SDanielle Ratson devlink_port_attrs_set(devlink_port, &attrs); 138776eea6c2SJakub Kicinski err = devl_port_register(priv_to_devlink(nsim_dev), devlink_port, 1388814b9ce6SDmytro Linkin nsim_dev_port->port_index); 13898320d145SJiri Pirko if (err) 13908320d145SJiri Pirko goto err_port_free; 13918320d145SJiri Pirko 13928320d145SJiri Pirko err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 13938320d145SJiri Pirko if (err) 13948320d145SJiri Pirko goto err_dl_port_unregister; 13958320d145SJiri Pirko 1396e05b2d14SJiri Pirko nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 1397e05b2d14SJiri Pirko if (IS_ERR(nsim_dev_port->ns)) { 1398e05b2d14SJiri Pirko err = PTR_ERR(nsim_dev_port->ns); 1399e05b2d14SJiri Pirko goto err_port_debugfs_exit; 1400e05b2d14SJiri Pirko } 1401e05b2d14SJiri Pirko 1402885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 140376eea6c2SJakub Kicinski err = devl_rate_leaf_create(&nsim_dev_port->devlink_port, 1404*f2fc15e2SMichal Wilczynski nsim_dev_port, NULL); 1405885dfe12SDmytro Linkin if (err) 1406885dfe12SDmytro Linkin goto err_nsim_destroy; 1407885dfe12SDmytro Linkin } 1408885dfe12SDmytro Linkin 14098320d145SJiri Pirko list_add(&nsim_dev_port->list, &nsim_dev->port_list); 14108320d145SJiri Pirko 14118320d145SJiri Pirko return 0; 14128320d145SJiri Pirko 1413885dfe12SDmytro Linkin err_nsim_destroy: 1414885dfe12SDmytro Linkin nsim_destroy(nsim_dev_port->ns); 1415e05b2d14SJiri Pirko err_port_debugfs_exit: 1416e05b2d14SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 14178320d145SJiri Pirko err_dl_port_unregister: 141876eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14198320d145SJiri Pirko err_port_free: 14208320d145SJiri Pirko kfree(nsim_dev_port); 14218320d145SJiri Pirko return err; 14228320d145SJiri Pirko } 14238320d145SJiri Pirko 1424794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 14258320d145SJiri Pirko { 14268320d145SJiri Pirko struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 14278320d145SJiri Pirko 14288320d145SJiri Pirko list_del(&nsim_dev_port->list); 1429885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 143076eea6c2SJakub Kicinski devl_rate_leaf_destroy(&nsim_dev_port->devlink_port); 1431e05b2d14SJiri Pirko nsim_destroy(nsim_dev_port->ns); 14328320d145SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 143376eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14348320d145SJiri Pirko kfree(nsim_dev_port); 14358320d145SJiri Pirko } 14368320d145SJiri Pirko 14378320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 14388320d145SJiri Pirko { 14398320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port, *tmp; 14408320d145SJiri Pirko 14418320d145SJiri Pirko list_for_each_entry_safe(nsim_dev_port, tmp, 14428320d145SJiri Pirko &nsim_dev->port_list, list) 1443794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 14448320d145SJiri Pirko } 14458320d145SJiri Pirko 14467f36a77aSJiri Pirko static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, 14477f36a77aSJiri Pirko unsigned int port_count) 14488320d145SJiri Pirko { 14497f36a77aSJiri Pirko int i, err; 14508320d145SJiri Pirko 14517f36a77aSJiri Pirko for (i = 0; i < port_count; i++) { 1452814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); 14538320d145SJiri Pirko if (err) 14548320d145SJiri Pirko goto err_port_del_all; 14558320d145SJiri Pirko } 14568320d145SJiri Pirko return 0; 14578320d145SJiri Pirko 14588320d145SJiri Pirko err_port_del_all: 14598320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 14608320d145SJiri Pirko return err; 14618320d145SJiri Pirko } 14628320d145SJiri Pirko 146375ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 146475ba029fSJiri Pirko struct netlink_ext_ack *extack) 146575ba029fSJiri Pirko { 146675ba029fSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 146775ba029fSJiri Pirko struct devlink *devlink; 146875ba029fSJiri Pirko int err; 146975ba029fSJiri Pirko 147075ba029fSJiri Pirko devlink = priv_to_devlink(nsim_dev); 147175ba029fSJiri Pirko nsim_dev = devlink_priv(devlink); 147275ba029fSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 147375ba029fSJiri Pirko nsim_dev->fw_update_status = true; 1474cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 147575ba029fSJiri Pirko 147675ba029fSJiri Pirko nsim_devlink_param_load_driverinit_values(devlink); 147775ba029fSJiri Pirko 147875ba029fSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 147975ba029fSJiri Pirko if (err) 1480f57ab5b7SIdo Schimmel return err; 148175ba029fSJiri Pirko 148275ba029fSJiri Pirko err = nsim_dev_traps_init(devlink); 148375ba029fSJiri Pirko if (err) 148475ba029fSJiri Pirko goto err_dummy_region_exit; 148575ba029fSJiri Pirko 1486f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, extack); 1487f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1488f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1489f57ab5b7SIdo Schimmel goto err_traps_exit; 1490f57ab5b7SIdo Schimmel } 1491f57ab5b7SIdo Schimmel 149282c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 149375ba029fSJiri Pirko if (err) 1494f57ab5b7SIdo Schimmel goto err_fib_destroy; 149575ba029fSJiri Pirko 1496a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 149782c93a87SJiri Pirko if (err) 149882c93a87SJiri Pirko goto err_health_exit; 149982c93a87SJiri Pirko 15001a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1501a8700c3dSIdo Schimmel if (err) 1502a8700c3dSIdo Schimmel goto err_psample_exit; 1503a8700c3dSIdo Schimmel 15041a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 15051a6d7ae7SPetr Machata if (err) 15061a6d7ae7SPetr Machata goto err_hwstats_exit; 15071a6d7ae7SPetr Machata 15088526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 15098526ad96STaehee Yoo 0200, 15108526ad96STaehee Yoo nsim_dev->ddir, 15118526ad96STaehee Yoo nsim_dev, 15128526ad96STaehee Yoo &nsim_dev_take_snapshot_fops); 151375ba029fSJiri Pirko return 0; 151475ba029fSJiri Pirko 15151a6d7ae7SPetr Machata err_hwstats_exit: 15161a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1517a8700c3dSIdo Schimmel err_psample_exit: 1518a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 151982c93a87SJiri Pirko err_health_exit: 152082c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1521f57ab5b7SIdo Schimmel err_fib_destroy: 1522f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 152375ba029fSJiri Pirko err_traps_exit: 152475ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 152575ba029fSJiri Pirko err_dummy_region_exit: 152675ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 152775ba029fSJiri Pirko return err; 152875ba029fSJiri Pirko } 152975ba029fSJiri Pirko 1530a66f64b8SJakub Kicinski int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) 15317f36a77aSJiri Pirko { 15327f36a77aSJiri Pirko struct nsim_dev *nsim_dev; 15337f36a77aSJiri Pirko struct devlink *devlink; 15347f36a77aSJiri Pirko int err; 15357f36a77aSJiri Pirko 153626713455SLeon Romanovsky devlink = devlink_alloc_ns(&nsim_dev_devlink_ops, sizeof(*nsim_dev), 1537919d13a7SLeon Romanovsky nsim_bus_dev->initial_net, &nsim_bus_dev->dev); 15387f36a77aSJiri Pirko if (!devlink) 1539bfcccfe7SJakub Kicinski return -ENOMEM; 1540012ec02aSJiri Pirko devl_lock(devlink); 15417f36a77aSJiri Pirko nsim_dev = devlink_priv(devlink); 15427f36a77aSJiri Pirko nsim_dev->nsim_bus_dev = nsim_bus_dev; 15437f36a77aSJiri Pirko nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 15447f36a77aSJiri Pirko get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 15457f36a77aSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 15467f36a77aSJiri Pirko nsim_dev->fw_update_status = true; 1547cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 15487f36a77aSJiri Pirko nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; 15497f36a77aSJiri Pirko nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; 1550d3cbb907SJiri Pirko spin_lock_init(&nsim_dev->fa_cookie_lock); 15517f36a77aSJiri Pirko 1552bfcccfe7SJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 1553bfcccfe7SJakub Kicinski 15545e388f3dSJakub Kicinski nsim_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 15555e388f3dSJakub Kicinski sizeof(struct nsim_vf_config), 15565e388f3dSJakub Kicinski GFP_KERNEL | __GFP_NOWARN); 15575e388f3dSJakub Kicinski if (!nsim_dev->vfconfigs) { 15585e388f3dSJakub Kicinski err = -ENOMEM; 1559012ec02aSJiri Pirko goto err_devlink_unlock; 15605e388f3dSJakub Kicinski } 15615e388f3dSJakub Kicinski 15627f36a77aSJiri Pirko err = nsim_dev_resources_register(devlink); 15637f36a77aSJiri Pirko if (err) 15645e388f3dSJakub Kicinski goto err_vfc_free; 15657f36a77aSJiri Pirko 15667f36a77aSJiri Pirko err = devlink_params_register(devlink, nsim_devlink_params, 15677f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 15687f36a77aSJiri Pirko if (err) 15697f36a77aSJiri Pirko goto err_dl_unregister; 15707f36a77aSJiri Pirko nsim_devlink_set_params_init_values(nsim_dev, devlink); 15717f36a77aSJiri Pirko 15727f36a77aSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 15737f36a77aSJiri Pirko if (err) 15747f36a77aSJiri Pirko goto err_params_unregister; 15757f36a77aSJiri Pirko 15767f36a77aSJiri Pirko err = nsim_dev_traps_init(devlink); 15777f36a77aSJiri Pirko if (err) 15787f36a77aSJiri Pirko goto err_dummy_region_exit; 15797f36a77aSJiri Pirko 15807f36a77aSJiri Pirko err = nsim_dev_debugfs_init(nsim_dev); 15817f36a77aSJiri Pirko if (err) 15827f36a77aSJiri Pirko goto err_traps_exit; 15837f36a77aSJiri Pirko 1584f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, NULL); 1585f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1586f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1587f57ab5b7SIdo Schimmel goto err_debugfs_exit; 1588f57ab5b7SIdo Schimmel } 1589f57ab5b7SIdo Schimmel 159082c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 15917f36a77aSJiri Pirko if (err) 1592f57ab5b7SIdo Schimmel goto err_fib_destroy; 15937f36a77aSJiri Pirko 159482c93a87SJiri Pirko err = nsim_bpf_dev_init(nsim_dev); 159582c93a87SJiri Pirko if (err) 159682c93a87SJiri Pirko goto err_health_exit; 159782c93a87SJiri Pirko 1598a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 15997f36a77aSJiri Pirko if (err) 16007f36a77aSJiri Pirko goto err_bpf_dev_exit; 16017f36a77aSJiri Pirko 16021a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1603a8700c3dSIdo Schimmel if (err) 1604a8700c3dSIdo Schimmel goto err_psample_exit; 1605a8700c3dSIdo Schimmel 16061a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 16071a6d7ae7SPetr Machata if (err) 16081a6d7ae7SPetr Machata goto err_hwstats_exit; 16091a6d7ae7SPetr Machata 1610160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 1611bd032e35SLeon Romanovsky devlink_set_features(devlink, DEVLINK_F_RELOAD); 1612012ec02aSJiri Pirko devl_unlock(devlink); 161371c1b525SLeon Romanovsky devlink_register(devlink); 1614bfcccfe7SJakub Kicinski return 0; 16157f36a77aSJiri Pirko 16161a6d7ae7SPetr Machata err_hwstats_exit: 16171a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1618a8700c3dSIdo Schimmel err_psample_exit: 1619a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 16207f36a77aSJiri Pirko err_bpf_dev_exit: 16217f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 162282c93a87SJiri Pirko err_health_exit: 162382c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1624f57ab5b7SIdo Schimmel err_fib_destroy: 1625f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 16267f36a77aSJiri Pirko err_debugfs_exit: 16277f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16287f36a77aSJiri Pirko err_traps_exit: 16297f36a77aSJiri Pirko nsim_dev_traps_exit(devlink); 16307f36a77aSJiri Pirko err_dummy_region_exit: 16317f36a77aSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 16327f36a77aSJiri Pirko err_params_unregister: 16337f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16347f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 16357f36a77aSJiri Pirko err_dl_unregister: 1636012ec02aSJiri Pirko devl_resources_unregister(devlink); 16375e388f3dSJakub Kicinski err_vfc_free: 16385e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 1639012ec02aSJiri Pirko err_devlink_unlock: 1640012ec02aSJiri Pirko devl_unlock(devlink); 16417f36a77aSJiri Pirko devlink_free(devlink); 16425e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 1643bfcccfe7SJakub Kicinski return err; 16447f36a77aSJiri Pirko } 16457f36a77aSJiri Pirko 164675ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) 164775ba029fSJiri Pirko { 164875ba029fSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 164975ba029fSJiri Pirko 165075ba029fSJiri Pirko if (devlink_is_reload_failed(devlink)) 165175ba029fSJiri Pirko return; 16528526ad96STaehee Yoo debugfs_remove(nsim_dev->take_snapshot); 165332ac15d8SDmytro Linkin 16541c401078SJakub Kicinski if (nsim_dev_get_vfs(nsim_dev)) { 16551c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_dev->nsim_bus_dev, 0); 16561c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) 16571c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 16581c401078SJakub Kicinski } 165932ac15d8SDmytro Linkin 166075ba029fSJiri Pirko nsim_dev_port_del_all(nsim_dev); 16611a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1662a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 166382c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1664f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 166575ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 166675ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 166775ba029fSJiri Pirko } 166875ba029fSJiri Pirko 1669a66f64b8SJakub Kicinski void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev) 16707f36a77aSJiri Pirko { 1671bfcccfe7SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 16727f36a77aSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 16737f36a77aSJiri Pirko 167471c1b525SLeon Romanovsky devlink_unregister(devlink); 1675012ec02aSJiri Pirko devl_lock(devlink); 167675ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 167775ba029fSJiri Pirko 16787f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 16797f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16807f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16817f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 1682012ec02aSJiri Pirko devl_resources_unregister(devlink); 16835e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 1684064bc731SWang Yufen kfree(nsim_dev->fa_cookie); 1685012ec02aSJiri Pirko devl_unlock(devlink); 16867f36a77aSJiri Pirko devlink_free(devlink); 16875e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 16887f36a77aSJiri Pirko } 16897f36a77aSJiri Pirko 1690794b2c05SJiri Pirko static struct nsim_dev_port * 1691814b9ce6SDmytro Linkin __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1692814b9ce6SDmytro Linkin unsigned int port_index) 1693794b2c05SJiri Pirko { 1694794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1695794b2c05SJiri Pirko 1696814b9ce6SDmytro Linkin port_index = nsim_dev_port_index(type, port_index); 1697794b2c05SJiri Pirko list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 1698794b2c05SJiri Pirko if (nsim_dev_port->port_index == port_index) 1699794b2c05SJiri Pirko return nsim_dev_port; 1700794b2c05SJiri Pirko return NULL; 1701794b2c05SJiri Pirko } 1702794b2c05SJiri Pirko 1703a66f64b8SJakub Kicinski int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1704794b2c05SJiri Pirko unsigned int port_index) 1705794b2c05SJiri Pirko { 1706794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1707794b2c05SJiri Pirko int err; 1708794b2c05SJiri Pirko 170976eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1710814b9ce6SDmytro Linkin if (__nsim_dev_port_lookup(nsim_dev, type, port_index)) 1711794b2c05SJiri Pirko err = -EEXIST; 1712794b2c05SJiri Pirko else 1713814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, type, port_index); 171476eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1715794b2c05SJiri Pirko return err; 1716794b2c05SJiri Pirko } 1717794b2c05SJiri Pirko 1718a66f64b8SJakub Kicinski int nsim_drv_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1719794b2c05SJiri Pirko unsigned int port_index) 1720794b2c05SJiri Pirko { 1721794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1722794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1723794b2c05SJiri Pirko int err = 0; 1724794b2c05SJiri Pirko 172576eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1726814b9ce6SDmytro Linkin nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index); 1727794b2c05SJiri Pirko if (!nsim_dev_port) 1728794b2c05SJiri Pirko err = -ENOENT; 1729794b2c05SJiri Pirko else 1730794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 173176eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1732794b2c05SJiri Pirko return err; 1733794b2c05SJiri Pirko } 1734794b2c05SJiri Pirko 17351c401078SJakub Kicinski int nsim_drv_configure_vfs(struct nsim_bus_dev *nsim_bus_dev, 17361c401078SJakub Kicinski unsigned int num_vfs) 17371c401078SJakub Kicinski { 17381c401078SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1739aff3a925SJakub Kicinski struct devlink *devlink = priv_to_devlink(nsim_dev); 1740047304d0SJakub Kicinski int ret = 0; 17411c401078SJakub Kicinski 1742aff3a925SJakub Kicinski devl_lock(devlink); 1743047304d0SJakub Kicinski if (nsim_bus_dev->num_vfs == num_vfs) 17441c401078SJakub Kicinski goto exit_unlock; 17451c401078SJakub Kicinski if (nsim_bus_dev->num_vfs && num_vfs) { 17461c401078SJakub Kicinski ret = -EBUSY; 17471c401078SJakub Kicinski goto exit_unlock; 17481c401078SJakub Kicinski } 17491c401078SJakub Kicinski if (nsim_bus_dev->max_vfs < num_vfs) { 17501c401078SJakub Kicinski ret = -ENOMEM; 17511c401078SJakub Kicinski goto exit_unlock; 17521c401078SJakub Kicinski } 17531c401078SJakub Kicinski 17541c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, num_vfs); 17551c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) { 17561c401078SJakub Kicinski if (num_vfs) { 17571c401078SJakub Kicinski ret = nsim_esw_switchdev_enable(nsim_dev, NULL); 17581c401078SJakub Kicinski if (ret) { 17591c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 17601c401078SJakub Kicinski goto exit_unlock; 17611c401078SJakub Kicinski } 17621c401078SJakub Kicinski } else { 17631c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 17641c401078SJakub Kicinski } 17651c401078SJakub Kicinski } 17661c401078SJakub Kicinski 17671c401078SJakub Kicinski exit_unlock: 1768aff3a925SJakub Kicinski devl_unlock(devlink); 17691c401078SJakub Kicinski 17701c401078SJakub Kicinski return ret; 17711c401078SJakub Kicinski } 17721c401078SJakub Kicinski 1773d514f41eSJiri Pirko int nsim_dev_init(void) 1774d514f41eSJiri Pirko { 1775ab1d0cc0SJiri Pirko nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 177634611e69Skbuild test robot return PTR_ERR_OR_ZERO(nsim_dev_ddir); 1777d514f41eSJiri Pirko } 1778d514f41eSJiri Pirko 1779d514f41eSJiri Pirko void nsim_dev_exit(void) 1780d514f41eSJiri Pirko { 1781d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev_ddir); 1782d514f41eSJiri Pirko } 1783