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 */ 439*012ec02aSJiri 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 448*012ec02aSJiri 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 456*012ec02aSJiri 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 */ 465*012ec02aSJiri 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 474*012ec02aSJiri 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 482*012ec02aSJiri 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 */ 491*012ec02aSJiri 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 = 560*012ec02aSJiri 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 { 568*012ec02aSJiri 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 */ 835*012ec02aSJiri Pirko if (!devl_trylock(priv_to_devlink(nsim_dev))) { 836*012ec02aSJiri Pirko schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 0); 837*012ec02aSJiri Pirko return; 838*012ec02aSJiri Pirko } 839*012ec02aSJiri 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 887*012ec02aSJiri 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 892*012ec02aSJiri 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 897*012ec02aSJiri 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: 910*012ec02aSJiri Pirko devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, 911b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 912ad188458SIdo Schimmel err_trap_policers_unregister: 913*012ec02aSJiri 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); 930*012ec02aSJiri Pirko devl_traps_unregister(devlink, nsim_traps_arr, 931da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr)); 932*012ec02aSJiri Pirko devl_trap_groups_unregister(devlink, nsim_trap_groups_arr, 933b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 934*012ec02aSJiri 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 951*012ec02aSJiri Pirko devl_lock(devlink); 952155ddfc5SJiri Pirko if (nsim_dev->dont_allow_reload) { 953155ddfc5SJiri Pirko /* For testing purposes, user set debugfs dont_allow_reload 954155ddfc5SJiri Pirko * value to true. So forbid it. 955155ddfc5SJiri Pirko */ 956f9867b51SColin Ian King NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); 957*012ec02aSJiri Pirko devl_unlock(devlink); 958155ddfc5SJiri Pirko return -EOPNOTSUPP; 959155ddfc5SJiri Pirko } 960155ddfc5SJiri Pirko 96175ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 962*012ec02aSJiri Pirko devl_unlock(devlink); 96397691069SJiri Pirko return 0; 96497691069SJiri Pirko } 96597691069SJiri Pirko 966ccdf0721SMoshe Shemesh static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action, 967dc64cc7cSMoshe Shemesh enum devlink_reload_limit limit, u32 *actions_performed, 968dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 9698fb4bc6fSJiri Pirko { 970a5facc4cSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 9715c0418edSLeon Romanovsky int ret; 9725c0418edSLeon Romanovsky 973*012ec02aSJiri Pirko devl_lock(devlink); 974155ddfc5SJiri Pirko if (nsim_dev->fail_reload) { 975155ddfc5SJiri Pirko /* For testing purposes, user set debugfs fail_reload 976155ddfc5SJiri Pirko * value to true. Fail right away. 977155ddfc5SJiri Pirko */ 978155ddfc5SJiri Pirko NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); 979*012ec02aSJiri Pirko devl_unlock(devlink); 980155ddfc5SJiri Pirko return -EINVAL; 981155ddfc5SJiri Pirko } 982155ddfc5SJiri Pirko 983ccdf0721SMoshe Shemesh *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 9845c0418edSLeon Romanovsky ret = nsim_dev_reload_create(nsim_dev, extack); 985*012ec02aSJiri Pirko devl_unlock(devlink); 9865c0418edSLeon Romanovsky return ret; 9878fb4bc6fSJiri Pirko } 9888fb4bc6fSJiri Pirko 9898e23cc03SJiri Pirko static int nsim_dev_info_get(struct devlink *devlink, 9908e23cc03SJiri Pirko struct devlink_info_req *req, 9918e23cc03SJiri Pirko struct netlink_ext_ack *extack) 9928e23cc03SJiri Pirko { 9938e23cc03SJiri Pirko return devlink_info_driver_name_put(req, DRV_NAME); 9948e23cc03SJiri Pirko } 9958e23cc03SJiri Pirko 996fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000 997fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 998fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 999fa4dfc4aSJiri Pirko 1000bc75c054SJacob Keller static int nsim_dev_flash_update(struct devlink *devlink, 1001bc75c054SJacob Keller struct devlink_flash_update_params *params, 1002fa4dfc4aSJiri Pirko struct netlink_ext_ack *extack) 1003fa4dfc4aSJiri Pirko { 1004fa4dfc4aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 1005fa4dfc4aSJiri Pirko int i; 1006fa4dfc4aSJiri Pirko 1007cbb58368SJacob Keller if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0) 1008cbb58368SJacob Keller return -EOPNOTSUPP; 1009cbb58368SJacob Keller 1010fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1011fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, 1012fa4dfc4aSJiri Pirko "Preparing to flash", 1013bc75c054SJacob Keller params->component, 0, 0); 1014fa4dfc4aSJiri Pirko } 1015fa4dfc4aSJiri Pirko 1016fa4dfc4aSJiri Pirko for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 1017fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) 1018fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1019bc75c054SJacob Keller params->component, 1020fa4dfc4aSJiri Pirko i * NSIM_DEV_FLASH_CHUNK_SIZE, 1021fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1022fa4dfc4aSJiri Pirko msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 1023fa4dfc4aSJiri Pirko } 1024fa4dfc4aSJiri Pirko 1025fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1026fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1027bc75c054SJacob Keller params->component, 1028fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE, 1029fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1030b311b001SShannon Nelson devlink_flash_update_timeout_notify(devlink, "Flash select", 1031bc75c054SJacob Keller params->component, 81); 1032fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing done", 1033bc75c054SJacob Keller params->component, 0, 0); 1034fa4dfc4aSJiri Pirko } 1035fa4dfc4aSJiri Pirko 1036fa4dfc4aSJiri Pirko return 0; 1037fa4dfc4aSJiri Pirko } 1038fa4dfc4aSJiri Pirko 1039da58f90fSIdo Schimmel static struct nsim_trap_item * 1040da58f90fSIdo Schimmel nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id) 1041da58f90fSIdo Schimmel { 1042da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data; 1043da58f90fSIdo Schimmel int i; 1044da58f90fSIdo Schimmel 1045da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 1046da58f90fSIdo Schimmel if (nsim_traps_arr[i].id == trap_id) 1047da58f90fSIdo Schimmel return &nsim_trap_data->trap_items_arr[i]; 1048da58f90fSIdo Schimmel } 1049da58f90fSIdo Schimmel 1050da58f90fSIdo Schimmel return NULL; 1051da58f90fSIdo Schimmel } 1052da58f90fSIdo Schimmel 1053da58f90fSIdo Schimmel static int nsim_dev_devlink_trap_init(struct devlink *devlink, 1054da58f90fSIdo Schimmel const struct devlink_trap *trap, 1055da58f90fSIdo Schimmel void *trap_ctx) 1056da58f90fSIdo Schimmel { 1057da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1058da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1059da58f90fSIdo Schimmel 1060da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1061da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1062da58f90fSIdo Schimmel return -ENOENT; 1063da58f90fSIdo Schimmel 1064da58f90fSIdo Schimmel nsim_trap_item->trap_ctx = trap_ctx; 1065da58f90fSIdo Schimmel nsim_trap_item->action = trap->init_action; 1066da58f90fSIdo Schimmel 1067da58f90fSIdo Schimmel return 0; 1068da58f90fSIdo Schimmel } 1069da58f90fSIdo Schimmel 1070da58f90fSIdo Schimmel static int 1071da58f90fSIdo Schimmel nsim_dev_devlink_trap_action_set(struct devlink *devlink, 1072da58f90fSIdo Schimmel const struct devlink_trap *trap, 1073c88e11e0SIdo Schimmel enum devlink_trap_action action, 1074c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 1075da58f90fSIdo Schimmel { 1076da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1077da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1078da58f90fSIdo Schimmel 1079da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1080da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1081da58f90fSIdo Schimmel return -ENOENT; 1082da58f90fSIdo Schimmel 1083da58f90fSIdo Schimmel spin_lock(&nsim_dev->trap_data->trap_lock); 1084da58f90fSIdo Schimmel nsim_trap_item->action = action; 1085da58f90fSIdo Schimmel spin_unlock(&nsim_dev->trap_data->trap_lock); 1086da58f90fSIdo Schimmel 1087da58f90fSIdo Schimmel return 0; 1088da58f90fSIdo Schimmel } 1089da58f90fSIdo Schimmel 1090ad188458SIdo Schimmel static int 10910dc8249aSIdo Schimmel nsim_dev_devlink_trap_group_set(struct devlink *devlink, 10920dc8249aSIdo Schimmel const struct devlink_trap_group *group, 1093c88e11e0SIdo Schimmel const struct devlink_trap_policer *policer, 1094c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 10950dc8249aSIdo Schimmel { 10960dc8249aSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 10970dc8249aSIdo Schimmel 10980dc8249aSIdo Schimmel if (nsim_dev->fail_trap_group_set) 10990dc8249aSIdo Schimmel return -EINVAL; 11000dc8249aSIdo Schimmel 11010dc8249aSIdo Schimmel return 0; 11020dc8249aSIdo Schimmel } 11030dc8249aSIdo Schimmel 11040dc8249aSIdo Schimmel static int 1105ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_set(struct devlink *devlink, 1106ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1107ad188458SIdo Schimmel u64 rate, u64 burst, 1108ad188458SIdo Schimmel struct netlink_ext_ack *extack) 1109ad188458SIdo Schimmel { 1110ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1111ad188458SIdo Schimmel 1112ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_set) { 1113ad188458SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes"); 1114ad188458SIdo Schimmel return -EINVAL; 1115ad188458SIdo Schimmel } 1116ad188458SIdo Schimmel 1117ad188458SIdo Schimmel return 0; 1118ad188458SIdo Schimmel } 1119ad188458SIdo Schimmel 1120ad188458SIdo Schimmel static int 1121ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink, 1122ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1123ad188458SIdo Schimmel u64 *p_drops) 1124ad188458SIdo Schimmel { 1125ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1126ad188458SIdo Schimmel u64 *cnt; 1127ad188458SIdo Schimmel 1128ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_counter_get) 1129ad188458SIdo Schimmel return -EINVAL; 1130ad188458SIdo Schimmel 1131ad188458SIdo Schimmel cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1]; 1132be43224fSIdo Schimmel *p_drops = (*cnt)++; 1133ad188458SIdo Schimmel 1134ad188458SIdo Schimmel return 0; 1135ad188458SIdo Schimmel } 1136ad188458SIdo Schimmel 1137605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_MAX 5000 /* Mbps */ 1138605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_UNIT 125000 /* 1 Mbps given in bytes/sec to avoid 1139605c4f8fSDmytro Linkin * u64 overflow during conversion from 1140605c4f8fSDmytro Linkin * bytes to bits. 1141605c4f8fSDmytro Linkin */ 1142605c4f8fSDmytro Linkin 1143605c4f8fSDmytro Linkin static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack) 1144605c4f8fSDmytro Linkin { 1145605c4f8fSDmytro Linkin u64 val; 1146605c4f8fSDmytro Linkin u32 rem; 1147605c4f8fSDmytro Linkin 1148605c4f8fSDmytro Linkin val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem); 1149605c4f8fSDmytro Linkin if (rem) { 1150605c4f8fSDmytro Linkin pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n", 1151605c4f8fSDmytro Linkin name, *rate); 1152605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps."); 1153605c4f8fSDmytro Linkin return -EINVAL; 1154605c4f8fSDmytro Linkin } 1155605c4f8fSDmytro Linkin 1156605c4f8fSDmytro Linkin if (val > NSIM_LINK_SPEED_MAX) { 1157605c4f8fSDmytro Linkin pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n", 1158605c4f8fSDmytro Linkin name, val); 1159605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps."); 1160605c4f8fSDmytro Linkin return -EINVAL; 1161605c4f8fSDmytro Linkin } 1162605c4f8fSDmytro Linkin *rate = val; 1163605c4f8fSDmytro Linkin return 0; 1164605c4f8fSDmytro Linkin } 1165605c4f8fSDmytro Linkin 1166605c4f8fSDmytro Linkin static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1167605c4f8fSDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1168605c4f8fSDmytro Linkin { 1169605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11705e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1171605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1172605c4f8fSDmytro Linkin int err; 1173605c4f8fSDmytro Linkin 1174605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1175605c4f8fSDmytro Linkin if (err) 1176605c4f8fSDmytro Linkin return err; 1177605c4f8fSDmytro Linkin 11785e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].min_tx_rate = tx_share; 1179605c4f8fSDmytro Linkin return 0; 1180605c4f8fSDmytro Linkin } 1181605c4f8fSDmytro Linkin 1182605c4f8fSDmytro Linkin static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1183605c4f8fSDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1184605c4f8fSDmytro Linkin { 1185605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11865e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1187605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1188605c4f8fSDmytro Linkin int err; 1189605c4f8fSDmytro Linkin 1190605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1191605c4f8fSDmytro Linkin if (err) 1192605c4f8fSDmytro Linkin return err; 1193605c4f8fSDmytro Linkin 11945e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].max_tx_rate = tx_max; 1195605c4f8fSDmytro Linkin return 0; 1196605c4f8fSDmytro Linkin } 1197605c4f8fSDmytro Linkin 1198885226f5SDmytro Linkin struct nsim_rate_node { 1199885226f5SDmytro Linkin struct dentry *ddir; 1200f3d101b4SDmytro Linkin struct dentry *rate_parent; 1201f3d101b4SDmytro Linkin char *parent_name; 1202885226f5SDmytro Linkin u16 tx_share; 1203885226f5SDmytro Linkin u16 tx_max; 1204885226f5SDmytro Linkin }; 1205885226f5SDmytro Linkin 1206885226f5SDmytro Linkin static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1207885226f5SDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1208885226f5SDmytro Linkin { 1209885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1210885226f5SDmytro Linkin int err; 1211885226f5SDmytro Linkin 1212885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1213885226f5SDmytro Linkin if (err) 1214885226f5SDmytro Linkin return err; 1215885226f5SDmytro Linkin 1216885226f5SDmytro Linkin nsim_node->tx_share = tx_share; 1217885226f5SDmytro Linkin return 0; 1218885226f5SDmytro Linkin } 1219885226f5SDmytro Linkin 1220885226f5SDmytro Linkin static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1221885226f5SDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1222885226f5SDmytro Linkin { 1223885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1224885226f5SDmytro Linkin int err; 1225885226f5SDmytro Linkin 1226885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1227885226f5SDmytro Linkin if (err) 1228885226f5SDmytro Linkin return err; 1229885226f5SDmytro Linkin 1230885226f5SDmytro Linkin nsim_node->tx_max = tx_max; 1231885226f5SDmytro Linkin return 0; 1232885226f5SDmytro Linkin } 1233885226f5SDmytro Linkin 1234885226f5SDmytro Linkin static int nsim_rate_node_new(struct devlink_rate *node, void **priv, 1235885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1236885226f5SDmytro Linkin { 1237885226f5SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(node->devlink); 1238885226f5SDmytro Linkin struct nsim_rate_node *nsim_node; 1239885226f5SDmytro Linkin 1240885226f5SDmytro Linkin if (!nsim_esw_mode_is_switchdev(nsim_dev)) { 1241885226f5SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode."); 1242885226f5SDmytro Linkin return -EOPNOTSUPP; 1243885226f5SDmytro Linkin } 1244885226f5SDmytro Linkin 1245885226f5SDmytro Linkin nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL); 1246885226f5SDmytro Linkin if (!nsim_node) 1247885226f5SDmytro Linkin return -ENOMEM; 1248885226f5SDmytro Linkin 1249885226f5SDmytro Linkin nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir); 12504e744cb8SDan Carpenter 1251885226f5SDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share); 1252885226f5SDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max); 1253f3d101b4SDmytro Linkin nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400, 1254f3d101b4SDmytro Linkin nsim_node->ddir, 1255f3d101b4SDmytro Linkin &nsim_node->parent_name, 1256f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 1257f3d101b4SDmytro Linkin 1258885226f5SDmytro Linkin *priv = nsim_node; 1259885226f5SDmytro Linkin return 0; 1260885226f5SDmytro Linkin } 1261885226f5SDmytro Linkin 1262885226f5SDmytro Linkin static int nsim_rate_node_del(struct devlink_rate *node, void *priv, 1263885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1264885226f5SDmytro Linkin { 1265885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1266885226f5SDmytro Linkin 1267f3d101b4SDmytro Linkin debugfs_remove(nsim_node->rate_parent); 1268885226f5SDmytro Linkin debugfs_remove_recursive(nsim_node->ddir); 1269885226f5SDmytro Linkin kfree(nsim_node); 1270885226f5SDmytro Linkin return 0; 1271885226f5SDmytro Linkin } 1272885226f5SDmytro Linkin 1273f3d101b4SDmytro Linkin static int nsim_rate_leaf_parent_set(struct devlink_rate *child, 1274f3d101b4SDmytro Linkin struct devlink_rate *parent, 1275f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1276f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1277f3d101b4SDmytro Linkin { 1278f3d101b4SDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv_child; 1279f3d101b4SDmytro Linkin 1280f3d101b4SDmytro Linkin if (parent) 1281f3d101b4SDmytro Linkin nsim_dev_port->parent_name = parent->name; 1282f3d101b4SDmytro Linkin else 1283f3d101b4SDmytro Linkin nsim_dev_port->parent_name = NULL; 1284f3d101b4SDmytro Linkin return 0; 1285f3d101b4SDmytro Linkin } 1286f3d101b4SDmytro Linkin 1287f3d101b4SDmytro Linkin static int nsim_rate_node_parent_set(struct devlink_rate *child, 1288f3d101b4SDmytro Linkin struct devlink_rate *parent, 1289f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1290f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1291f3d101b4SDmytro Linkin { 1292f3d101b4SDmytro Linkin struct nsim_rate_node *nsim_node = priv_child; 1293f3d101b4SDmytro Linkin 1294f3d101b4SDmytro Linkin if (parent) 1295f3d101b4SDmytro Linkin nsim_node->parent_name = parent->name; 1296f3d101b4SDmytro Linkin else 1297f3d101b4SDmytro Linkin nsim_node->parent_name = NULL; 1298f3d101b4SDmytro Linkin return 0; 1299f3d101b4SDmytro Linkin } 1300f3d101b4SDmytro Linkin 1301a7b3527aSOleksandr Mazur static int 1302275b51c2SOleksandr Mazur nsim_dev_devlink_trap_drop_counter_get(struct devlink *devlink, 1303a7b3527aSOleksandr Mazur const struct devlink_trap *trap, 1304a7b3527aSOleksandr Mazur u64 *p_drops) 1305a7b3527aSOleksandr Mazur { 1306a7b3527aSOleksandr Mazur struct nsim_dev *nsim_dev = devlink_priv(devlink); 1307a7b3527aSOleksandr Mazur u64 *cnt; 1308a7b3527aSOleksandr Mazur 1309275b51c2SOleksandr Mazur if (nsim_dev->fail_trap_drop_counter_get) 1310a7b3527aSOleksandr Mazur return -EINVAL; 1311a7b3527aSOleksandr Mazur 1312a7b3527aSOleksandr Mazur cnt = &nsim_dev->trap_data->trap_pkt_cnt; 1313a7b3527aSOleksandr Mazur *p_drops = (*cnt)++; 1314a7b3527aSOleksandr Mazur 1315a7b3527aSOleksandr Mazur return 0; 1316a7b3527aSOleksandr Mazur } 1317a7b3527aSOleksandr Mazur 13188fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 1319160dc373SDmytro Linkin .eswitch_mode_set = nsim_devlink_eswitch_mode_set, 1320160dc373SDmytro Linkin .eswitch_mode_get = nsim_devlink_eswitch_mode_get, 1321cbb58368SJacob Keller .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT | 1322cbb58368SJacob Keller DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, 1323ccdf0721SMoshe Shemesh .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), 132497691069SJiri Pirko .reload_down = nsim_dev_reload_down, 132597691069SJiri Pirko .reload_up = nsim_dev_reload_up, 13268e23cc03SJiri Pirko .info_get = nsim_dev_info_get, 1327fa4dfc4aSJiri Pirko .flash_update = nsim_dev_flash_update, 1328da58f90fSIdo Schimmel .trap_init = nsim_dev_devlink_trap_init, 1329da58f90fSIdo Schimmel .trap_action_set = nsim_dev_devlink_trap_action_set, 13300dc8249aSIdo Schimmel .trap_group_set = nsim_dev_devlink_trap_group_set, 1331ad188458SIdo Schimmel .trap_policer_set = nsim_dev_devlink_trap_policer_set, 1332ad188458SIdo Schimmel .trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get, 1333605c4f8fSDmytro Linkin .rate_leaf_tx_share_set = nsim_leaf_tx_share_set, 1334605c4f8fSDmytro Linkin .rate_leaf_tx_max_set = nsim_leaf_tx_max_set, 1335885226f5SDmytro Linkin .rate_node_tx_share_set = nsim_node_tx_share_set, 1336885226f5SDmytro Linkin .rate_node_tx_max_set = nsim_node_tx_max_set, 1337885226f5SDmytro Linkin .rate_node_new = nsim_rate_node_new, 1338885226f5SDmytro Linkin .rate_node_del = nsim_rate_node_del, 1339f3d101b4SDmytro Linkin .rate_leaf_parent_set = nsim_rate_leaf_parent_set, 1340f3d101b4SDmytro Linkin .rate_node_parent_set = nsim_rate_node_parent_set, 1341275b51c2SOleksandr Mazur .trap_drop_counter_get = nsim_dev_devlink_trap_drop_counter_get, 13428fb4bc6fSJiri Pirko }; 13438fb4bc6fSJiri Pirko 1344150e8f8aSJiri Pirko #define NSIM_DEV_MAX_MACS_DEFAULT 32 1345150e8f8aSJiri Pirko #define NSIM_DEV_TEST1_DEFAULT true 1346150e8f8aSJiri Pirko 1347814b9ce6SDmytro Linkin static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1348794b2c05SJiri Pirko unsigned int port_index) 13498320d145SJiri Pirko { 135071ad8d55SDanielle Ratson struct devlink_port_attrs attrs = {}; 13518320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port; 13528320d145SJiri Pirko struct devlink_port *devlink_port; 13538320d145SJiri Pirko int err; 13548320d145SJiri Pirko 13555e388f3dSJakub Kicinski if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_dev_get_vfs(nsim_dev)) 135692ba1f29SDmytro Linkin return -EINVAL; 135792ba1f29SDmytro Linkin 13588320d145SJiri Pirko nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); 13598320d145SJiri Pirko if (!nsim_dev_port) 13608320d145SJiri Pirko return -ENOMEM; 1361814b9ce6SDmytro Linkin nsim_dev_port->port_index = nsim_dev_port_index(type, port_index); 1362814b9ce6SDmytro Linkin nsim_dev_port->port_type = type; 13638320d145SJiri Pirko 13648320d145SJiri Pirko devlink_port = &nsim_dev_port->devlink_port; 136592ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) { 136671ad8d55SDanielle Ratson attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 136771ad8d55SDanielle Ratson attrs.phys.port_number = port_index + 1; 136892ba1f29SDmytro Linkin } else { 136992ba1f29SDmytro Linkin attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; 137092ba1f29SDmytro Linkin attrs.pci_vf.pf = 0; 137192ba1f29SDmytro Linkin attrs.pci_vf.vf = port_index; 137292ba1f29SDmytro Linkin } 137371ad8d55SDanielle Ratson memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 137471ad8d55SDanielle Ratson attrs.switch_id.id_len = nsim_dev->switch_id.id_len; 137571ad8d55SDanielle Ratson devlink_port_attrs_set(devlink_port, &attrs); 137676eea6c2SJakub Kicinski err = devl_port_register(priv_to_devlink(nsim_dev), devlink_port, 1377814b9ce6SDmytro Linkin nsim_dev_port->port_index); 13788320d145SJiri Pirko if (err) 13798320d145SJiri Pirko goto err_port_free; 13808320d145SJiri Pirko 13818320d145SJiri Pirko err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 13828320d145SJiri Pirko if (err) 13838320d145SJiri Pirko goto err_dl_port_unregister; 13848320d145SJiri Pirko 1385e05b2d14SJiri Pirko nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 1386e05b2d14SJiri Pirko if (IS_ERR(nsim_dev_port->ns)) { 1387e05b2d14SJiri Pirko err = PTR_ERR(nsim_dev_port->ns); 1388e05b2d14SJiri Pirko goto err_port_debugfs_exit; 1389e05b2d14SJiri Pirko } 1390e05b2d14SJiri Pirko 1391885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 139276eea6c2SJakub Kicinski err = devl_rate_leaf_create(&nsim_dev_port->devlink_port, 1393885dfe12SDmytro Linkin nsim_dev_port); 1394885dfe12SDmytro Linkin if (err) 1395885dfe12SDmytro Linkin goto err_nsim_destroy; 1396885dfe12SDmytro Linkin } 1397885dfe12SDmytro Linkin 1398e05b2d14SJiri Pirko devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); 13998320d145SJiri Pirko list_add(&nsim_dev_port->list, &nsim_dev->port_list); 14008320d145SJiri Pirko 14018320d145SJiri Pirko return 0; 14028320d145SJiri Pirko 1403885dfe12SDmytro Linkin err_nsim_destroy: 1404885dfe12SDmytro Linkin nsim_destroy(nsim_dev_port->ns); 1405e05b2d14SJiri Pirko err_port_debugfs_exit: 1406e05b2d14SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 14078320d145SJiri Pirko err_dl_port_unregister: 140876eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14098320d145SJiri Pirko err_port_free: 14108320d145SJiri Pirko kfree(nsim_dev_port); 14118320d145SJiri Pirko return err; 14128320d145SJiri Pirko } 14138320d145SJiri Pirko 1414794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 14158320d145SJiri Pirko { 14168320d145SJiri Pirko struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 14178320d145SJiri Pirko 14188320d145SJiri Pirko list_del(&nsim_dev_port->list); 1419885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 142076eea6c2SJakub Kicinski devl_rate_leaf_destroy(&nsim_dev_port->devlink_port); 1421e05b2d14SJiri Pirko devlink_port_type_clear(devlink_port); 1422e05b2d14SJiri Pirko nsim_destroy(nsim_dev_port->ns); 14238320d145SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 142476eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14258320d145SJiri Pirko kfree(nsim_dev_port); 14268320d145SJiri Pirko } 14278320d145SJiri Pirko 14288320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 14298320d145SJiri Pirko { 14308320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port, *tmp; 14318320d145SJiri Pirko 14328320d145SJiri Pirko list_for_each_entry_safe(nsim_dev_port, tmp, 14338320d145SJiri Pirko &nsim_dev->port_list, list) 1434794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 14358320d145SJiri Pirko } 14368320d145SJiri Pirko 14377f36a77aSJiri Pirko static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, 14387f36a77aSJiri Pirko unsigned int port_count) 14398320d145SJiri Pirko { 14407f36a77aSJiri Pirko int i, err; 14418320d145SJiri Pirko 14427f36a77aSJiri Pirko for (i = 0; i < port_count; i++) { 1443814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); 14448320d145SJiri Pirko if (err) 14458320d145SJiri Pirko goto err_port_del_all; 14468320d145SJiri Pirko } 14478320d145SJiri Pirko return 0; 14488320d145SJiri Pirko 14498320d145SJiri Pirko err_port_del_all: 14508320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 14518320d145SJiri Pirko return err; 14528320d145SJiri Pirko } 14538320d145SJiri Pirko 145475ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 145575ba029fSJiri Pirko struct netlink_ext_ack *extack) 145675ba029fSJiri Pirko { 145775ba029fSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 145875ba029fSJiri Pirko struct devlink *devlink; 145975ba029fSJiri Pirko int err; 146075ba029fSJiri Pirko 146175ba029fSJiri Pirko devlink = priv_to_devlink(nsim_dev); 146275ba029fSJiri Pirko nsim_dev = devlink_priv(devlink); 146375ba029fSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 146475ba029fSJiri Pirko nsim_dev->fw_update_status = true; 1465cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 146675ba029fSJiri Pirko 146775ba029fSJiri Pirko nsim_devlink_param_load_driverinit_values(devlink); 146875ba029fSJiri Pirko 146975ba029fSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 147075ba029fSJiri Pirko if (err) 1471f57ab5b7SIdo Schimmel return err; 147275ba029fSJiri Pirko 147375ba029fSJiri Pirko err = nsim_dev_traps_init(devlink); 147475ba029fSJiri Pirko if (err) 147575ba029fSJiri Pirko goto err_dummy_region_exit; 147675ba029fSJiri Pirko 1477f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, extack); 1478f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1479f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1480f57ab5b7SIdo Schimmel goto err_traps_exit; 1481f57ab5b7SIdo Schimmel } 1482f57ab5b7SIdo Schimmel 148382c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 148475ba029fSJiri Pirko if (err) 1485f57ab5b7SIdo Schimmel goto err_fib_destroy; 148675ba029fSJiri Pirko 1487a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 148882c93a87SJiri Pirko if (err) 148982c93a87SJiri Pirko goto err_health_exit; 149082c93a87SJiri Pirko 14911a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1492a8700c3dSIdo Schimmel if (err) 1493a8700c3dSIdo Schimmel goto err_psample_exit; 1494a8700c3dSIdo Schimmel 14951a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 14961a6d7ae7SPetr Machata if (err) 14971a6d7ae7SPetr Machata goto err_hwstats_exit; 14981a6d7ae7SPetr Machata 14998526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 15008526ad96STaehee Yoo 0200, 15018526ad96STaehee Yoo nsim_dev->ddir, 15028526ad96STaehee Yoo nsim_dev, 15038526ad96STaehee Yoo &nsim_dev_take_snapshot_fops); 150475ba029fSJiri Pirko return 0; 150575ba029fSJiri Pirko 15061a6d7ae7SPetr Machata err_hwstats_exit: 15071a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1508a8700c3dSIdo Schimmel err_psample_exit: 1509a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 151082c93a87SJiri Pirko err_health_exit: 151182c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1512f57ab5b7SIdo Schimmel err_fib_destroy: 1513f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 151475ba029fSJiri Pirko err_traps_exit: 151575ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 151675ba029fSJiri Pirko err_dummy_region_exit: 151775ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 151875ba029fSJiri Pirko return err; 151975ba029fSJiri Pirko } 152075ba029fSJiri Pirko 1521a66f64b8SJakub Kicinski int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) 15227f36a77aSJiri Pirko { 15237f36a77aSJiri Pirko struct nsim_dev *nsim_dev; 15247f36a77aSJiri Pirko struct devlink *devlink; 15257f36a77aSJiri Pirko int err; 15267f36a77aSJiri Pirko 152726713455SLeon Romanovsky devlink = devlink_alloc_ns(&nsim_dev_devlink_ops, sizeof(*nsim_dev), 1528919d13a7SLeon Romanovsky nsim_bus_dev->initial_net, &nsim_bus_dev->dev); 15297f36a77aSJiri Pirko if (!devlink) 1530bfcccfe7SJakub Kicinski return -ENOMEM; 1531*012ec02aSJiri Pirko devl_lock(devlink); 15327f36a77aSJiri Pirko nsim_dev = devlink_priv(devlink); 15337f36a77aSJiri Pirko nsim_dev->nsim_bus_dev = nsim_bus_dev; 15347f36a77aSJiri Pirko nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 15357f36a77aSJiri Pirko get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 15367f36a77aSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 15377f36a77aSJiri Pirko nsim_dev->fw_update_status = true; 1538cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 15397f36a77aSJiri Pirko nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; 15407f36a77aSJiri Pirko nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; 1541d3cbb907SJiri Pirko spin_lock_init(&nsim_dev->fa_cookie_lock); 15427f36a77aSJiri Pirko 1543bfcccfe7SJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 1544bfcccfe7SJakub Kicinski 15455e388f3dSJakub Kicinski nsim_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 15465e388f3dSJakub Kicinski sizeof(struct nsim_vf_config), 15475e388f3dSJakub Kicinski GFP_KERNEL | __GFP_NOWARN); 15485e388f3dSJakub Kicinski if (!nsim_dev->vfconfigs) { 15495e388f3dSJakub Kicinski err = -ENOMEM; 1550*012ec02aSJiri Pirko goto err_devlink_unlock; 15515e388f3dSJakub Kicinski } 15525e388f3dSJakub Kicinski 15537f36a77aSJiri Pirko err = nsim_dev_resources_register(devlink); 15547f36a77aSJiri Pirko if (err) 15555e388f3dSJakub Kicinski goto err_vfc_free; 15567f36a77aSJiri Pirko 15577f36a77aSJiri Pirko err = devlink_params_register(devlink, nsim_devlink_params, 15587f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 15597f36a77aSJiri Pirko if (err) 15607f36a77aSJiri Pirko goto err_dl_unregister; 15617f36a77aSJiri Pirko nsim_devlink_set_params_init_values(nsim_dev, devlink); 15627f36a77aSJiri Pirko 15637f36a77aSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 15647f36a77aSJiri Pirko if (err) 15657f36a77aSJiri Pirko goto err_params_unregister; 15667f36a77aSJiri Pirko 15677f36a77aSJiri Pirko err = nsim_dev_traps_init(devlink); 15687f36a77aSJiri Pirko if (err) 15697f36a77aSJiri Pirko goto err_dummy_region_exit; 15707f36a77aSJiri Pirko 15717f36a77aSJiri Pirko err = nsim_dev_debugfs_init(nsim_dev); 15727f36a77aSJiri Pirko if (err) 15737f36a77aSJiri Pirko goto err_traps_exit; 15747f36a77aSJiri Pirko 1575f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, NULL); 1576f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1577f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1578f57ab5b7SIdo Schimmel goto err_debugfs_exit; 1579f57ab5b7SIdo Schimmel } 1580f57ab5b7SIdo Schimmel 158182c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 15827f36a77aSJiri Pirko if (err) 1583f57ab5b7SIdo Schimmel goto err_fib_destroy; 15847f36a77aSJiri Pirko 158582c93a87SJiri Pirko err = nsim_bpf_dev_init(nsim_dev); 158682c93a87SJiri Pirko if (err) 158782c93a87SJiri Pirko goto err_health_exit; 158882c93a87SJiri Pirko 1589a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 15907f36a77aSJiri Pirko if (err) 15917f36a77aSJiri Pirko goto err_bpf_dev_exit; 15927f36a77aSJiri Pirko 15931a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1594a8700c3dSIdo Schimmel if (err) 1595a8700c3dSIdo Schimmel goto err_psample_exit; 1596a8700c3dSIdo Schimmel 15971a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 15981a6d7ae7SPetr Machata if (err) 15991a6d7ae7SPetr Machata goto err_hwstats_exit; 16001a6d7ae7SPetr Machata 1601160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 1602bd032e35SLeon Romanovsky devlink_set_features(devlink, DEVLINK_F_RELOAD); 1603*012ec02aSJiri Pirko devl_unlock(devlink); 160471c1b525SLeon Romanovsky devlink_register(devlink); 1605bfcccfe7SJakub Kicinski return 0; 16067f36a77aSJiri Pirko 16071a6d7ae7SPetr Machata err_hwstats_exit: 16081a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1609a8700c3dSIdo Schimmel err_psample_exit: 1610a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 16117f36a77aSJiri Pirko err_bpf_dev_exit: 16127f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 161382c93a87SJiri Pirko err_health_exit: 161482c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1615f57ab5b7SIdo Schimmel err_fib_destroy: 1616f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 16177f36a77aSJiri Pirko err_debugfs_exit: 16187f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16197f36a77aSJiri Pirko err_traps_exit: 16207f36a77aSJiri Pirko nsim_dev_traps_exit(devlink); 16217f36a77aSJiri Pirko err_dummy_region_exit: 16227f36a77aSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 16237f36a77aSJiri Pirko err_params_unregister: 16247f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16257f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 16267f36a77aSJiri Pirko err_dl_unregister: 1627*012ec02aSJiri Pirko devl_resources_unregister(devlink); 16285e388f3dSJakub Kicinski err_vfc_free: 16295e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 1630*012ec02aSJiri Pirko err_devlink_unlock: 1631*012ec02aSJiri Pirko devl_unlock(devlink); 16327f36a77aSJiri Pirko devlink_free(devlink); 16335e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 1634bfcccfe7SJakub Kicinski return err; 16357f36a77aSJiri Pirko } 16367f36a77aSJiri Pirko 163775ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) 163875ba029fSJiri Pirko { 163975ba029fSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 164075ba029fSJiri Pirko 164175ba029fSJiri Pirko if (devlink_is_reload_failed(devlink)) 164275ba029fSJiri Pirko return; 16438526ad96STaehee Yoo debugfs_remove(nsim_dev->take_snapshot); 164432ac15d8SDmytro Linkin 16451c401078SJakub Kicinski if (nsim_dev_get_vfs(nsim_dev)) { 16461c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_dev->nsim_bus_dev, 0); 16471c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) 16481c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 16491c401078SJakub Kicinski } 165032ac15d8SDmytro Linkin 165175ba029fSJiri Pirko nsim_dev_port_del_all(nsim_dev); 16521a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1653a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 165482c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1655f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 165675ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 165775ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 165875ba029fSJiri Pirko } 165975ba029fSJiri Pirko 1660a66f64b8SJakub Kicinski void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev) 16617f36a77aSJiri Pirko { 1662bfcccfe7SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 16637f36a77aSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 16647f36a77aSJiri Pirko 166571c1b525SLeon Romanovsky devlink_unregister(devlink); 1666*012ec02aSJiri Pirko devl_lock(devlink); 166775ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 166875ba029fSJiri Pirko 16697f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 16707f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16717f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16727f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 1673*012ec02aSJiri Pirko devl_resources_unregister(devlink); 16745e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 1675*012ec02aSJiri Pirko devl_unlock(devlink); 16767f36a77aSJiri Pirko devlink_free(devlink); 16775e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 16787f36a77aSJiri Pirko } 16797f36a77aSJiri Pirko 1680794b2c05SJiri Pirko static struct nsim_dev_port * 1681814b9ce6SDmytro Linkin __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1682814b9ce6SDmytro Linkin unsigned int port_index) 1683794b2c05SJiri Pirko { 1684794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1685794b2c05SJiri Pirko 1686814b9ce6SDmytro Linkin port_index = nsim_dev_port_index(type, port_index); 1687794b2c05SJiri Pirko list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 1688794b2c05SJiri Pirko if (nsim_dev_port->port_index == port_index) 1689794b2c05SJiri Pirko return nsim_dev_port; 1690794b2c05SJiri Pirko return NULL; 1691794b2c05SJiri Pirko } 1692794b2c05SJiri Pirko 1693a66f64b8SJakub Kicinski int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1694794b2c05SJiri Pirko unsigned int port_index) 1695794b2c05SJiri Pirko { 1696794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1697794b2c05SJiri Pirko int err; 1698794b2c05SJiri Pirko 169976eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1700814b9ce6SDmytro Linkin if (__nsim_dev_port_lookup(nsim_dev, type, port_index)) 1701794b2c05SJiri Pirko err = -EEXIST; 1702794b2c05SJiri Pirko else 1703814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, type, port_index); 170476eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1705794b2c05SJiri Pirko return err; 1706794b2c05SJiri Pirko } 1707794b2c05SJiri Pirko 1708a66f64b8SJakub Kicinski int nsim_drv_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1709794b2c05SJiri Pirko unsigned int port_index) 1710794b2c05SJiri Pirko { 1711794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1712794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1713794b2c05SJiri Pirko int err = 0; 1714794b2c05SJiri Pirko 171576eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1716814b9ce6SDmytro Linkin nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index); 1717794b2c05SJiri Pirko if (!nsim_dev_port) 1718794b2c05SJiri Pirko err = -ENOENT; 1719794b2c05SJiri Pirko else 1720794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 172176eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1722794b2c05SJiri Pirko return err; 1723794b2c05SJiri Pirko } 1724794b2c05SJiri Pirko 17251c401078SJakub Kicinski int nsim_drv_configure_vfs(struct nsim_bus_dev *nsim_bus_dev, 17261c401078SJakub Kicinski unsigned int num_vfs) 17271c401078SJakub Kicinski { 17281c401078SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1729aff3a925SJakub Kicinski struct devlink *devlink = priv_to_devlink(nsim_dev); 1730047304d0SJakub Kicinski int ret = 0; 17311c401078SJakub Kicinski 1732aff3a925SJakub Kicinski devl_lock(devlink); 1733047304d0SJakub Kicinski if (nsim_bus_dev->num_vfs == num_vfs) 17341c401078SJakub Kicinski goto exit_unlock; 17351c401078SJakub Kicinski if (nsim_bus_dev->num_vfs && num_vfs) { 17361c401078SJakub Kicinski ret = -EBUSY; 17371c401078SJakub Kicinski goto exit_unlock; 17381c401078SJakub Kicinski } 17391c401078SJakub Kicinski if (nsim_bus_dev->max_vfs < num_vfs) { 17401c401078SJakub Kicinski ret = -ENOMEM; 17411c401078SJakub Kicinski goto exit_unlock; 17421c401078SJakub Kicinski } 17431c401078SJakub Kicinski 17441c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, num_vfs); 17451c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) { 17461c401078SJakub Kicinski if (num_vfs) { 17471c401078SJakub Kicinski ret = nsim_esw_switchdev_enable(nsim_dev, NULL); 17481c401078SJakub Kicinski if (ret) { 17491c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 17501c401078SJakub Kicinski goto exit_unlock; 17511c401078SJakub Kicinski } 17521c401078SJakub Kicinski } else { 17531c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 17541c401078SJakub Kicinski } 17551c401078SJakub Kicinski } 17561c401078SJakub Kicinski 17571c401078SJakub Kicinski exit_unlock: 1758aff3a925SJakub Kicinski devl_unlock(devlink); 17591c401078SJakub Kicinski 17601c401078SJakub Kicinski return ret; 17611c401078SJakub Kicinski } 17621c401078SJakub Kicinski 1763d514f41eSJiri Pirko int nsim_dev_init(void) 1764d514f41eSJiri Pirko { 1765ab1d0cc0SJiri Pirko nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 176634611e69Skbuild test robot return PTR_ERR_OR_ZERO(nsim_dev_ddir); 1767d514f41eSJiri Pirko } 1768d514f41eSJiri Pirko 1769d514f41eSJiri Pirko void nsim_dev_exit(void) 1770d514f41eSJiri Pirko { 1771d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev_ddir); 1772d514f41eSJiri Pirko } 1773