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() && 62*aff3a925SJakub 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; 278*aff3a925SJakub 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 } 288*aff3a925SJakub 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); 342*aff3a925SJakub 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 */ 4398fb4bc6fSJiri Pirko err = devlink_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 448a5facc4cSJiri Pirko err = devlink_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 456a5facc4cSJiri Pirko err = devlink_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 */ 4658fb4bc6fSJiri Pirko err = devlink_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 474a5facc4cSJiri Pirko err = devlink_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 482a5facc4cSJiri Pirko err = devlink_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 */ 49135266255SIdo Schimmel err = devlink_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 = 560e8937681SJacob Keller devlink_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 { 5684418f862SJiri Pirko devlink_region_destroy(nsim_dev->dummy_region); 5694418f862SJiri Pirko } 5704418f862SJiri Pirko 571*aff3a925SJakub Kicinski static int 572*aff3a925SJakub Kicinski __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 573*aff3a925SJakub 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 582*aff3a925SJakub 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 { 593*aff3a925SJakub 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++) { 597*aff3a925SJakub 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: 608*aff3a925SJakub Kicinski list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) 609*aff3a925SJakub Kicinski if (nsim_dev_port_is_vf(nsim_dev_port)) 610*aff3a925SJakub 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 int err = 0; 619160dc373SDmytro Linkin 620*aff3a925SJakub Kicinski devl_lock(devlink); 621160dc373SDmytro Linkin if (mode == nsim_dev->esw_mode) 622160dc373SDmytro Linkin goto unlock; 623160dc373SDmytro Linkin 624160dc373SDmytro Linkin if (mode == DEVLINK_ESWITCH_MODE_LEGACY) 625160dc373SDmytro Linkin err = nsim_esw_legacy_enable(nsim_dev, extack); 626160dc373SDmytro Linkin else if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) 627160dc373SDmytro Linkin err = nsim_esw_switchdev_enable(nsim_dev, extack); 628160dc373SDmytro Linkin else 629160dc373SDmytro Linkin err = -EINVAL; 630160dc373SDmytro Linkin 631160dc373SDmytro Linkin unlock: 632*aff3a925SJakub Kicinski devl_unlock(devlink); 633160dc373SDmytro Linkin return err; 634160dc373SDmytro Linkin } 635160dc373SDmytro Linkin 636160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) 637160dc373SDmytro Linkin { 638160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 639160dc373SDmytro Linkin 640160dc373SDmytro Linkin *mode = nsim_dev->esw_mode; 641160dc373SDmytro Linkin return 0; 642160dc373SDmytro Linkin } 643160dc373SDmytro Linkin 644da58f90fSIdo Schimmel struct nsim_trap_item { 645da58f90fSIdo Schimmel void *trap_ctx; 646da58f90fSIdo Schimmel enum devlink_trap_action action; 647da58f90fSIdo Schimmel }; 648da58f90fSIdo Schimmel 649da58f90fSIdo Schimmel struct nsim_trap_data { 650da58f90fSIdo Schimmel struct delayed_work trap_report_dw; 651da58f90fSIdo Schimmel struct nsim_trap_item *trap_items_arr; 652ad188458SIdo Schimmel u64 *trap_policers_cnt_arr; 653a7b3527aSOleksandr Mazur u64 trap_pkt_cnt; 654da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 655da58f90fSIdo Schimmel spinlock_t trap_lock; /* Protects trap_items_arr */ 656da58f90fSIdo Schimmel }; 657da58f90fSIdo Schimmel 6589e087457SIdo Schimmel /* All driver-specific traps must be documented in 65904e4272cSJacob Keller * Documentation/networking/devlink/netdevsim.rst 6609e087457SIdo Schimmel */ 661da58f90fSIdo Schimmel enum { 662da58f90fSIdo Schimmel NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX, 663da58f90fSIdo Schimmel NSIM_TRAP_ID_FID_MISS, 664da58f90fSIdo Schimmel }; 665da58f90fSIdo Schimmel 666da58f90fSIdo Schimmel #define NSIM_TRAP_NAME_FID_MISS "fid_miss" 667da58f90fSIdo Schimmel 668da58f90fSIdo Schimmel #define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT 669da58f90fSIdo Schimmel 670da58f90fSIdo Schimmel #define NSIM_TRAP_DROP(_id, _group_id) \ 671da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 672107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 673da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 674d3cbb907SJiri Pirko #define NSIM_TRAP_DROP_EXT(_id, _group_id, _metadata) \ 675d3cbb907SJiri Pirko DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 676107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 677d3cbb907SJiri Pirko NSIM_TRAP_METADATA | (_metadata)) 678da58f90fSIdo Schimmel #define NSIM_TRAP_EXCEPTION(_id, _group_id) \ 679da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ 680107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 681da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 68218979367SIdo Schimmel #define NSIM_TRAP_CONTROL(_id, _group_id, _action) \ 68318979367SIdo Schimmel DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ 68418979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 68518979367SIdo Schimmel NSIM_TRAP_METADATA) 686da58f90fSIdo Schimmel #define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id) \ 687da58f90fSIdo Schimmel DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id, \ 688da58f90fSIdo Schimmel NSIM_TRAP_NAME_##_id, \ 689107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 690da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 691da58f90fSIdo Schimmel 692ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_RATE 1 693ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_RATE 8000 694ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_BURST 8 695ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_BURST 65536 696ad188458SIdo Schimmel 697ad188458SIdo Schimmel #define NSIM_TRAP_POLICER(_id, _rate, _burst) \ 698ad188458SIdo Schimmel DEVLINK_TRAP_POLICER(_id, _rate, _burst, \ 699ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_RATE, \ 700ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_RATE, \ 701ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_BURST, \ 702ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_BURST) 703ad188458SIdo Schimmel 704ad188458SIdo Schimmel static const struct devlink_trap_policer nsim_trap_policers_arr[] = { 705ad188458SIdo Schimmel NSIM_TRAP_POLICER(1, 1000, 128), 706ad188458SIdo Schimmel NSIM_TRAP_POLICER(2, 2000, 256), 707ad188458SIdo Schimmel NSIM_TRAP_POLICER(3, 3000, 512), 708ad188458SIdo Schimmel }; 709ad188458SIdo Schimmel 710b29545d8SIdo Schimmel static const struct devlink_trap_group nsim_trap_groups_arr[] = { 711f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), 712f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), 71385176f19SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), 714f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 2), 715f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 3), 71618979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 3), 717b29545d8SIdo Schimmel }; 718b29545d8SIdo Schimmel 719da58f90fSIdo Schimmel static const struct devlink_trap nsim_traps_arr[] = { 720da58f90fSIdo Schimmel NSIM_TRAP_DROP(SMAC_MC, L2_DROPS), 721da58f90fSIdo Schimmel NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 722da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 723da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 724da58f90fSIdo Schimmel NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 725da58f90fSIdo Schimmel NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 726da58f90fSIdo Schimmel NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS), 727da58f90fSIdo Schimmel NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 72885176f19SIdo Schimmel NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), 729da58f90fSIdo Schimmel NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS), 730d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, 731d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 732d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, 733d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 73418979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 73518979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, TRAP), 736da58f90fSIdo Schimmel }; 737da58f90fSIdo Schimmel 738da58f90fSIdo Schimmel #define NSIM_TRAP_L4_DATA_LEN 100 739da58f90fSIdo Schimmel 740da58f90fSIdo Schimmel static struct sk_buff *nsim_dev_trap_skb_build(void) 741da58f90fSIdo Schimmel { 742da58f90fSIdo Schimmel int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN; 743da58f90fSIdo Schimmel struct sk_buff *skb; 744da58f90fSIdo Schimmel struct udphdr *udph; 745da58f90fSIdo Schimmel struct ethhdr *eth; 746da58f90fSIdo Schimmel struct iphdr *iph; 747da58f90fSIdo Schimmel 748da58f90fSIdo Schimmel skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 749da58f90fSIdo Schimmel if (!skb) 750da58f90fSIdo Schimmel return NULL; 751da58f90fSIdo Schimmel tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len; 752da58f90fSIdo Schimmel 75358a406deSIdo Schimmel skb_reset_mac_header(skb); 754da58f90fSIdo Schimmel eth = skb_put(skb, sizeof(struct ethhdr)); 755da58f90fSIdo Schimmel eth_random_addr(eth->h_dest); 756da58f90fSIdo Schimmel eth_random_addr(eth->h_source); 757da58f90fSIdo Schimmel eth->h_proto = htons(ETH_P_IP); 758da58f90fSIdo Schimmel skb->protocol = htons(ETH_P_IP); 759da58f90fSIdo Schimmel 76058a406deSIdo Schimmel skb_set_network_header(skb, skb->len); 761da58f90fSIdo Schimmel iph = skb_put(skb, sizeof(struct iphdr)); 762da58f90fSIdo Schimmel iph->protocol = IPPROTO_UDP; 763da58f90fSIdo Schimmel iph->saddr = in_aton("192.0.2.1"); 764da58f90fSIdo Schimmel iph->daddr = in_aton("198.51.100.1"); 765da58f90fSIdo Schimmel iph->version = 0x4; 766da58f90fSIdo Schimmel iph->frag_off = 0; 767da58f90fSIdo Schimmel iph->ihl = 0x5; 768da58f90fSIdo Schimmel iph->tot_len = htons(tot_len); 769da58f90fSIdo Schimmel iph->ttl = 100; 770d9bd6d27SYueHaibing iph->check = 0; 771d9bd6d27SYueHaibing iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 772da58f90fSIdo Schimmel 77358a406deSIdo Schimmel skb_set_transport_header(skb, skb->len); 774da58f90fSIdo Schimmel udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len); 775da58f90fSIdo Schimmel get_random_bytes(&udph->source, sizeof(u16)); 776da58f90fSIdo Schimmel get_random_bytes(&udph->dest, sizeof(u16)); 777da58f90fSIdo Schimmel udph->len = htons(sizeof(struct udphdr) + data_len); 778da58f90fSIdo Schimmel 779da58f90fSIdo Schimmel return skb; 780da58f90fSIdo Schimmel } 781da58f90fSIdo Schimmel 782da58f90fSIdo Schimmel static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port) 783da58f90fSIdo Schimmel { 784da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 785da58f90fSIdo Schimmel struct devlink *devlink = priv_to_devlink(nsim_dev); 786da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 787da58f90fSIdo Schimmel int i; 788da58f90fSIdo Schimmel 789da58f90fSIdo Schimmel nsim_trap_data = nsim_dev->trap_data; 790da58f90fSIdo Schimmel 791da58f90fSIdo Schimmel spin_lock(&nsim_trap_data->trap_lock); 792da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 793d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie = NULL; 794da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 795da58f90fSIdo Schimmel struct sk_buff *skb; 796d3cbb907SJiri Pirko bool has_fa_cookie; 797d3cbb907SJiri Pirko 798d3cbb907SJiri Pirko has_fa_cookie = nsim_traps_arr[i].metadata_cap & 799d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE; 800da58f90fSIdo Schimmel 801da58f90fSIdo Schimmel nsim_trap_item = &nsim_trap_data->trap_items_arr[i]; 802da58f90fSIdo Schimmel if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP) 803da58f90fSIdo Schimmel continue; 804da58f90fSIdo Schimmel 805da58f90fSIdo Schimmel skb = nsim_dev_trap_skb_build(); 806da58f90fSIdo Schimmel if (!skb) 807da58f90fSIdo Schimmel continue; 808da58f90fSIdo Schimmel skb->dev = nsim_dev_port->ns->netdev; 809da58f90fSIdo Schimmel 810da58f90fSIdo Schimmel /* Trapped packets are usually passed to devlink in softIRQ, 811da58f90fSIdo Schimmel * but in this case they are generated in a workqueue. Disable 812da58f90fSIdo Schimmel * softIRQs to prevent lockdep from complaining about 813da58f90fSIdo Schimmel * "incosistent lock state". 814da58f90fSIdo Schimmel */ 815d3cbb907SJiri Pirko 816d3cbb907SJiri Pirko spin_lock_bh(&nsim_dev->fa_cookie_lock); 817d3cbb907SJiri Pirko fa_cookie = has_fa_cookie ? nsim_dev->fa_cookie : NULL; 818da58f90fSIdo Schimmel devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx, 819d3cbb907SJiri Pirko &nsim_dev_port->devlink_port, fa_cookie); 820d3cbb907SJiri Pirko spin_unlock_bh(&nsim_dev->fa_cookie_lock); 821da58f90fSIdo Schimmel consume_skb(skb); 822da58f90fSIdo Schimmel } 823da58f90fSIdo Schimmel spin_unlock(&nsim_trap_data->trap_lock); 824da58f90fSIdo Schimmel } 825da58f90fSIdo Schimmel 826da58f90fSIdo Schimmel #define NSIM_TRAP_REPORT_INTERVAL_MS 100 827da58f90fSIdo Schimmel 828da58f90fSIdo Schimmel static void nsim_dev_trap_report_work(struct work_struct *work) 829da58f90fSIdo Schimmel { 830da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 831da58f90fSIdo Schimmel struct nsim_dev_port *nsim_dev_port; 832da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 833da58f90fSIdo Schimmel 834da58f90fSIdo Schimmel nsim_trap_data = container_of(work, struct nsim_trap_data, 835da58f90fSIdo Schimmel trap_report_dw.work); 836da58f90fSIdo Schimmel nsim_dev = nsim_trap_data->nsim_dev; 837da58f90fSIdo Schimmel 838da58f90fSIdo Schimmel /* For each running port and enabled packet trap, generate a UDP 839da58f90fSIdo Schimmel * packet with a random 5-tuple and report it. 840da58f90fSIdo Schimmel */ 84176eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 842da58f90fSIdo Schimmel list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) { 843da58f90fSIdo Schimmel if (!netif_running(nsim_dev_port->ns->netdev)) 844da58f90fSIdo Schimmel continue; 845da58f90fSIdo Schimmel 846da58f90fSIdo Schimmel nsim_dev_trap_report(nsim_dev_port); 847da58f90fSIdo Schimmel } 84876eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 849da58f90fSIdo Schimmel 850da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 851da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 852da58f90fSIdo Schimmel } 853da58f90fSIdo Schimmel 854da58f90fSIdo Schimmel static int nsim_dev_traps_init(struct devlink *devlink) 855da58f90fSIdo Schimmel { 856ad188458SIdo Schimmel size_t policers_count = ARRAY_SIZE(nsim_trap_policers_arr); 857da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 858da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 859da58f90fSIdo Schimmel int err; 860da58f90fSIdo Schimmel 861da58f90fSIdo Schimmel nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL); 862da58f90fSIdo Schimmel if (!nsim_trap_data) 863da58f90fSIdo Schimmel return -ENOMEM; 864da58f90fSIdo Schimmel 865da58f90fSIdo Schimmel nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr), 866da58f90fSIdo Schimmel sizeof(struct nsim_trap_item), 867da58f90fSIdo Schimmel GFP_KERNEL); 868da58f90fSIdo Schimmel if (!nsim_trap_data->trap_items_arr) { 869da58f90fSIdo Schimmel err = -ENOMEM; 870da58f90fSIdo Schimmel goto err_trap_data_free; 871da58f90fSIdo Schimmel } 872da58f90fSIdo Schimmel 873ad188458SIdo Schimmel nsim_trap_data->trap_policers_cnt_arr = kcalloc(policers_count, 874ad188458SIdo Schimmel sizeof(u64), 875ad188458SIdo Schimmel GFP_KERNEL); 876ad188458SIdo Schimmel if (!nsim_trap_data->trap_policers_cnt_arr) { 877ad188458SIdo Schimmel err = -ENOMEM; 878ad188458SIdo Schimmel goto err_trap_items_free; 879ad188458SIdo Schimmel } 880ad188458SIdo Schimmel 881da58f90fSIdo Schimmel /* The lock is used to protect the action state of the registered 882da58f90fSIdo Schimmel * traps. The value is written by user and read in delayed work when 883da58f90fSIdo Schimmel * iterating over all the traps. 884da58f90fSIdo Schimmel */ 885da58f90fSIdo Schimmel spin_lock_init(&nsim_trap_data->trap_lock); 886da58f90fSIdo Schimmel nsim_trap_data->nsim_dev = nsim_dev; 887da58f90fSIdo Schimmel nsim_dev->trap_data = nsim_trap_data; 888da58f90fSIdo Schimmel 889ad188458SIdo Schimmel err = devlink_trap_policers_register(devlink, nsim_trap_policers_arr, 890ad188458SIdo Schimmel policers_count); 891ad188458SIdo Schimmel if (err) 892ad188458SIdo Schimmel goto err_trap_policers_cnt_free; 893ad188458SIdo Schimmel 894b29545d8SIdo Schimmel err = devlink_trap_groups_register(devlink, nsim_trap_groups_arr, 895b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 896b29545d8SIdo Schimmel if (err) 897ad188458SIdo Schimmel goto err_trap_policers_unregister; 898b29545d8SIdo Schimmel 899da58f90fSIdo Schimmel err = devlink_traps_register(devlink, nsim_traps_arr, 900da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr), NULL); 901da58f90fSIdo Schimmel if (err) 902b29545d8SIdo Schimmel goto err_trap_groups_unregister; 903da58f90fSIdo Schimmel 904da58f90fSIdo Schimmel INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw, 905da58f90fSIdo Schimmel nsim_dev_trap_report_work); 906da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 907da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 908da58f90fSIdo Schimmel 909da58f90fSIdo Schimmel return 0; 910da58f90fSIdo Schimmel 911b29545d8SIdo Schimmel err_trap_groups_unregister: 912b29545d8SIdo Schimmel devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, 913b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 914ad188458SIdo Schimmel err_trap_policers_unregister: 915ad188458SIdo Schimmel devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, 916ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 917ad188458SIdo Schimmel err_trap_policers_cnt_free: 918ad188458SIdo Schimmel kfree(nsim_trap_data->trap_policers_cnt_arr); 919da58f90fSIdo Schimmel err_trap_items_free: 920da58f90fSIdo Schimmel kfree(nsim_trap_data->trap_items_arr); 921da58f90fSIdo Schimmel err_trap_data_free: 922da58f90fSIdo Schimmel kfree(nsim_trap_data); 923da58f90fSIdo Schimmel return err; 924da58f90fSIdo Schimmel } 925da58f90fSIdo Schimmel 926da58f90fSIdo Schimmel static void nsim_dev_traps_exit(struct devlink *devlink) 927da58f90fSIdo Schimmel { 928da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 929da58f90fSIdo Schimmel 93076eea6c2SJakub Kicinski /* caution, trap work takes devlink lock */ 931da58f90fSIdo Schimmel cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw); 932da58f90fSIdo Schimmel devlink_traps_unregister(devlink, nsim_traps_arr, 933da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr)); 934b29545d8SIdo Schimmel devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, 935b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 936ad188458SIdo Schimmel devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, 937ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 938ad188458SIdo Schimmel kfree(nsim_dev->trap_data->trap_policers_cnt_arr); 939da58f90fSIdo Schimmel kfree(nsim_dev->trap_data->trap_items_arr); 940da58f90fSIdo Schimmel kfree(nsim_dev->trap_data); 941da58f90fSIdo Schimmel } 942da58f90fSIdo Schimmel 94375ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 94475ba029fSJiri Pirko struct netlink_ext_ack *extack); 94575ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); 94675ba029fSJiri Pirko 947070c63f2SJiri Pirko static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, 948dc64cc7cSMoshe Shemesh enum devlink_reload_action action, enum devlink_reload_limit limit, 949dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 95097691069SJiri Pirko { 95175ba029fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 95223809a72SLeon Romanovsky struct nsim_bus_dev *nsim_bus_dev; 95323809a72SLeon Romanovsky 95423809a72SLeon Romanovsky nsim_bus_dev = nsim_dev->nsim_bus_dev; 95523809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 95623809a72SLeon Romanovsky return -EOPNOTSUPP; 95775ba029fSJiri Pirko 958155ddfc5SJiri Pirko if (nsim_dev->dont_allow_reload) { 959155ddfc5SJiri Pirko /* For testing purposes, user set debugfs dont_allow_reload 960155ddfc5SJiri Pirko * value to true. So forbid it. 961155ddfc5SJiri Pirko */ 962f9867b51SColin Ian King NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); 96323809a72SLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 964155ddfc5SJiri Pirko return -EOPNOTSUPP; 965155ddfc5SJiri Pirko } 9665c0418edSLeon Romanovsky nsim_bus_dev->in_reload = true; 967155ddfc5SJiri Pirko 96875ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 96923809a72SLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 97097691069SJiri Pirko return 0; 97197691069SJiri Pirko } 97297691069SJiri Pirko 973ccdf0721SMoshe Shemesh static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action, 974dc64cc7cSMoshe Shemesh enum devlink_reload_limit limit, u32 *actions_performed, 975dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 9768fb4bc6fSJiri Pirko { 977a5facc4cSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 9785c0418edSLeon Romanovsky struct nsim_bus_dev *nsim_bus_dev; 9795c0418edSLeon Romanovsky int ret; 9805c0418edSLeon Romanovsky 9815c0418edSLeon Romanovsky nsim_bus_dev = nsim_dev->nsim_bus_dev; 9825c0418edSLeon Romanovsky mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 9835c0418edSLeon Romanovsky nsim_bus_dev->in_reload = false; 9848fb4bc6fSJiri Pirko 985155ddfc5SJiri Pirko if (nsim_dev->fail_reload) { 986155ddfc5SJiri Pirko /* For testing purposes, user set debugfs fail_reload 987155ddfc5SJiri Pirko * value to true. Fail right away. 988155ddfc5SJiri Pirko */ 989155ddfc5SJiri Pirko NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); 9905c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 991155ddfc5SJiri Pirko return -EINVAL; 992155ddfc5SJiri Pirko } 993155ddfc5SJiri Pirko 994ccdf0721SMoshe Shemesh *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 9955c0418edSLeon Romanovsky ret = nsim_dev_reload_create(nsim_dev, extack); 9965c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 9975c0418edSLeon Romanovsky return ret; 9988fb4bc6fSJiri Pirko } 9998fb4bc6fSJiri Pirko 10008e23cc03SJiri Pirko static int nsim_dev_info_get(struct devlink *devlink, 10018e23cc03SJiri Pirko struct devlink_info_req *req, 10028e23cc03SJiri Pirko struct netlink_ext_ack *extack) 10038e23cc03SJiri Pirko { 10048e23cc03SJiri Pirko return devlink_info_driver_name_put(req, DRV_NAME); 10058e23cc03SJiri Pirko } 10068e23cc03SJiri Pirko 1007fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000 1008fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 1009fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 1010fa4dfc4aSJiri Pirko 1011bc75c054SJacob Keller static int nsim_dev_flash_update(struct devlink *devlink, 1012bc75c054SJacob Keller struct devlink_flash_update_params *params, 1013fa4dfc4aSJiri Pirko struct netlink_ext_ack *extack) 1014fa4dfc4aSJiri Pirko { 1015fa4dfc4aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 1016fa4dfc4aSJiri Pirko int i; 1017fa4dfc4aSJiri Pirko 1018cbb58368SJacob Keller if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0) 1019cbb58368SJacob Keller return -EOPNOTSUPP; 1020cbb58368SJacob Keller 1021fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1022fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, 1023fa4dfc4aSJiri Pirko "Preparing to flash", 1024bc75c054SJacob Keller params->component, 0, 0); 1025fa4dfc4aSJiri Pirko } 1026fa4dfc4aSJiri Pirko 1027fa4dfc4aSJiri Pirko for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 1028fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) 1029fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1030bc75c054SJacob Keller params->component, 1031fa4dfc4aSJiri Pirko i * NSIM_DEV_FLASH_CHUNK_SIZE, 1032fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1033fa4dfc4aSJiri Pirko msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 1034fa4dfc4aSJiri Pirko } 1035fa4dfc4aSJiri Pirko 1036fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1037fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1038bc75c054SJacob Keller params->component, 1039fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE, 1040fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1041b311b001SShannon Nelson devlink_flash_update_timeout_notify(devlink, "Flash select", 1042bc75c054SJacob Keller params->component, 81); 1043fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing done", 1044bc75c054SJacob Keller params->component, 0, 0); 1045fa4dfc4aSJiri Pirko } 1046fa4dfc4aSJiri Pirko 1047fa4dfc4aSJiri Pirko return 0; 1048fa4dfc4aSJiri Pirko } 1049fa4dfc4aSJiri Pirko 1050da58f90fSIdo Schimmel static struct nsim_trap_item * 1051da58f90fSIdo Schimmel nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id) 1052da58f90fSIdo Schimmel { 1053da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data; 1054da58f90fSIdo Schimmel int i; 1055da58f90fSIdo Schimmel 1056da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 1057da58f90fSIdo Schimmel if (nsim_traps_arr[i].id == trap_id) 1058da58f90fSIdo Schimmel return &nsim_trap_data->trap_items_arr[i]; 1059da58f90fSIdo Schimmel } 1060da58f90fSIdo Schimmel 1061da58f90fSIdo Schimmel return NULL; 1062da58f90fSIdo Schimmel } 1063da58f90fSIdo Schimmel 1064da58f90fSIdo Schimmel static int nsim_dev_devlink_trap_init(struct devlink *devlink, 1065da58f90fSIdo Schimmel const struct devlink_trap *trap, 1066da58f90fSIdo Schimmel void *trap_ctx) 1067da58f90fSIdo Schimmel { 1068da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1069da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1070da58f90fSIdo Schimmel 1071da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1072da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1073da58f90fSIdo Schimmel return -ENOENT; 1074da58f90fSIdo Schimmel 1075da58f90fSIdo Schimmel nsim_trap_item->trap_ctx = trap_ctx; 1076da58f90fSIdo Schimmel nsim_trap_item->action = trap->init_action; 1077da58f90fSIdo Schimmel 1078da58f90fSIdo Schimmel return 0; 1079da58f90fSIdo Schimmel } 1080da58f90fSIdo Schimmel 1081da58f90fSIdo Schimmel static int 1082da58f90fSIdo Schimmel nsim_dev_devlink_trap_action_set(struct devlink *devlink, 1083da58f90fSIdo Schimmel const struct devlink_trap *trap, 1084c88e11e0SIdo Schimmel enum devlink_trap_action action, 1085c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 1086da58f90fSIdo Schimmel { 1087da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1088da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1089da58f90fSIdo Schimmel 1090da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1091da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1092da58f90fSIdo Schimmel return -ENOENT; 1093da58f90fSIdo Schimmel 1094da58f90fSIdo Schimmel spin_lock(&nsim_dev->trap_data->trap_lock); 1095da58f90fSIdo Schimmel nsim_trap_item->action = action; 1096da58f90fSIdo Schimmel spin_unlock(&nsim_dev->trap_data->trap_lock); 1097da58f90fSIdo Schimmel 1098da58f90fSIdo Schimmel return 0; 1099da58f90fSIdo Schimmel } 1100da58f90fSIdo Schimmel 1101ad188458SIdo Schimmel static int 11020dc8249aSIdo Schimmel nsim_dev_devlink_trap_group_set(struct devlink *devlink, 11030dc8249aSIdo Schimmel const struct devlink_trap_group *group, 1104c88e11e0SIdo Schimmel const struct devlink_trap_policer *policer, 1105c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 11060dc8249aSIdo Schimmel { 11070dc8249aSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 11080dc8249aSIdo Schimmel 11090dc8249aSIdo Schimmel if (nsim_dev->fail_trap_group_set) 11100dc8249aSIdo Schimmel return -EINVAL; 11110dc8249aSIdo Schimmel 11120dc8249aSIdo Schimmel return 0; 11130dc8249aSIdo Schimmel } 11140dc8249aSIdo Schimmel 11150dc8249aSIdo Schimmel static int 1116ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_set(struct devlink *devlink, 1117ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1118ad188458SIdo Schimmel u64 rate, u64 burst, 1119ad188458SIdo Schimmel struct netlink_ext_ack *extack) 1120ad188458SIdo Schimmel { 1121ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1122ad188458SIdo Schimmel 1123ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_set) { 1124ad188458SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes"); 1125ad188458SIdo Schimmel return -EINVAL; 1126ad188458SIdo Schimmel } 1127ad188458SIdo Schimmel 1128ad188458SIdo Schimmel return 0; 1129ad188458SIdo Schimmel } 1130ad188458SIdo Schimmel 1131ad188458SIdo Schimmel static int 1132ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink, 1133ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1134ad188458SIdo Schimmel u64 *p_drops) 1135ad188458SIdo Schimmel { 1136ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1137ad188458SIdo Schimmel u64 *cnt; 1138ad188458SIdo Schimmel 1139ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_counter_get) 1140ad188458SIdo Schimmel return -EINVAL; 1141ad188458SIdo Schimmel 1142ad188458SIdo Schimmel cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1]; 1143be43224fSIdo Schimmel *p_drops = (*cnt)++; 1144ad188458SIdo Schimmel 1145ad188458SIdo Schimmel return 0; 1146ad188458SIdo Schimmel } 1147ad188458SIdo Schimmel 1148605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_MAX 5000 /* Mbps */ 1149605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_UNIT 125000 /* 1 Mbps given in bytes/sec to avoid 1150605c4f8fSDmytro Linkin * u64 overflow during conversion from 1151605c4f8fSDmytro Linkin * bytes to bits. 1152605c4f8fSDmytro Linkin */ 1153605c4f8fSDmytro Linkin 1154605c4f8fSDmytro Linkin static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack) 1155605c4f8fSDmytro Linkin { 1156605c4f8fSDmytro Linkin u64 val; 1157605c4f8fSDmytro Linkin u32 rem; 1158605c4f8fSDmytro Linkin 1159605c4f8fSDmytro Linkin val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem); 1160605c4f8fSDmytro Linkin if (rem) { 1161605c4f8fSDmytro Linkin pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n", 1162605c4f8fSDmytro Linkin name, *rate); 1163605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps."); 1164605c4f8fSDmytro Linkin return -EINVAL; 1165605c4f8fSDmytro Linkin } 1166605c4f8fSDmytro Linkin 1167605c4f8fSDmytro Linkin if (val > NSIM_LINK_SPEED_MAX) { 1168605c4f8fSDmytro Linkin pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n", 1169605c4f8fSDmytro Linkin name, val); 1170605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps."); 1171605c4f8fSDmytro Linkin return -EINVAL; 1172605c4f8fSDmytro Linkin } 1173605c4f8fSDmytro Linkin *rate = val; 1174605c4f8fSDmytro Linkin return 0; 1175605c4f8fSDmytro Linkin } 1176605c4f8fSDmytro Linkin 1177605c4f8fSDmytro Linkin static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1178605c4f8fSDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1179605c4f8fSDmytro Linkin { 1180605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11815e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1182605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1183605c4f8fSDmytro Linkin int err; 1184605c4f8fSDmytro Linkin 1185605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1186605c4f8fSDmytro Linkin if (err) 1187605c4f8fSDmytro Linkin return err; 1188605c4f8fSDmytro Linkin 11895e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].min_tx_rate = tx_share; 1190605c4f8fSDmytro Linkin return 0; 1191605c4f8fSDmytro Linkin } 1192605c4f8fSDmytro Linkin 1193605c4f8fSDmytro Linkin static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1194605c4f8fSDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1195605c4f8fSDmytro Linkin { 1196605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11975e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1198605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1199605c4f8fSDmytro Linkin int err; 1200605c4f8fSDmytro Linkin 1201605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1202605c4f8fSDmytro Linkin if (err) 1203605c4f8fSDmytro Linkin return err; 1204605c4f8fSDmytro Linkin 12055e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].max_tx_rate = tx_max; 1206605c4f8fSDmytro Linkin return 0; 1207605c4f8fSDmytro Linkin } 1208605c4f8fSDmytro Linkin 1209885226f5SDmytro Linkin struct nsim_rate_node { 1210885226f5SDmytro Linkin struct dentry *ddir; 1211f3d101b4SDmytro Linkin struct dentry *rate_parent; 1212f3d101b4SDmytro Linkin char *parent_name; 1213885226f5SDmytro Linkin u16 tx_share; 1214885226f5SDmytro Linkin u16 tx_max; 1215885226f5SDmytro Linkin }; 1216885226f5SDmytro Linkin 1217885226f5SDmytro Linkin static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1218885226f5SDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1219885226f5SDmytro Linkin { 1220885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1221885226f5SDmytro Linkin int err; 1222885226f5SDmytro Linkin 1223885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1224885226f5SDmytro Linkin if (err) 1225885226f5SDmytro Linkin return err; 1226885226f5SDmytro Linkin 1227885226f5SDmytro Linkin nsim_node->tx_share = tx_share; 1228885226f5SDmytro Linkin return 0; 1229885226f5SDmytro Linkin } 1230885226f5SDmytro Linkin 1231885226f5SDmytro Linkin static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1232885226f5SDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1233885226f5SDmytro Linkin { 1234885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1235885226f5SDmytro Linkin int err; 1236885226f5SDmytro Linkin 1237885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1238885226f5SDmytro Linkin if (err) 1239885226f5SDmytro Linkin return err; 1240885226f5SDmytro Linkin 1241885226f5SDmytro Linkin nsim_node->tx_max = tx_max; 1242885226f5SDmytro Linkin return 0; 1243885226f5SDmytro Linkin } 1244885226f5SDmytro Linkin 1245885226f5SDmytro Linkin static int nsim_rate_node_new(struct devlink_rate *node, void **priv, 1246885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1247885226f5SDmytro Linkin { 1248885226f5SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(node->devlink); 1249885226f5SDmytro Linkin struct nsim_rate_node *nsim_node; 1250885226f5SDmytro Linkin 1251885226f5SDmytro Linkin if (!nsim_esw_mode_is_switchdev(nsim_dev)) { 1252885226f5SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode."); 1253885226f5SDmytro Linkin return -EOPNOTSUPP; 1254885226f5SDmytro Linkin } 1255885226f5SDmytro Linkin 1256885226f5SDmytro Linkin nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL); 1257885226f5SDmytro Linkin if (!nsim_node) 1258885226f5SDmytro Linkin return -ENOMEM; 1259885226f5SDmytro Linkin 1260885226f5SDmytro Linkin nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir); 12614e744cb8SDan Carpenter 1262885226f5SDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share); 1263885226f5SDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max); 1264f3d101b4SDmytro Linkin nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400, 1265f3d101b4SDmytro Linkin nsim_node->ddir, 1266f3d101b4SDmytro Linkin &nsim_node->parent_name, 1267f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 1268f3d101b4SDmytro Linkin 1269885226f5SDmytro Linkin *priv = nsim_node; 1270885226f5SDmytro Linkin return 0; 1271885226f5SDmytro Linkin } 1272885226f5SDmytro Linkin 1273885226f5SDmytro Linkin static int nsim_rate_node_del(struct devlink_rate *node, void *priv, 1274885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1275885226f5SDmytro Linkin { 1276885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1277885226f5SDmytro Linkin 1278f3d101b4SDmytro Linkin debugfs_remove(nsim_node->rate_parent); 1279885226f5SDmytro Linkin debugfs_remove_recursive(nsim_node->ddir); 1280885226f5SDmytro Linkin kfree(nsim_node); 1281885226f5SDmytro Linkin return 0; 1282885226f5SDmytro Linkin } 1283885226f5SDmytro Linkin 1284f3d101b4SDmytro Linkin static int nsim_rate_leaf_parent_set(struct devlink_rate *child, 1285f3d101b4SDmytro Linkin struct devlink_rate *parent, 1286f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1287f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1288f3d101b4SDmytro Linkin { 1289f3d101b4SDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv_child; 1290f3d101b4SDmytro Linkin 1291f3d101b4SDmytro Linkin if (parent) 1292f3d101b4SDmytro Linkin nsim_dev_port->parent_name = parent->name; 1293f3d101b4SDmytro Linkin else 1294f3d101b4SDmytro Linkin nsim_dev_port->parent_name = NULL; 1295f3d101b4SDmytro Linkin return 0; 1296f3d101b4SDmytro Linkin } 1297f3d101b4SDmytro Linkin 1298f3d101b4SDmytro Linkin static int nsim_rate_node_parent_set(struct devlink_rate *child, 1299f3d101b4SDmytro Linkin struct devlink_rate *parent, 1300f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1301f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1302f3d101b4SDmytro Linkin { 1303f3d101b4SDmytro Linkin struct nsim_rate_node *nsim_node = priv_child; 1304f3d101b4SDmytro Linkin 1305f3d101b4SDmytro Linkin if (parent) 1306f3d101b4SDmytro Linkin nsim_node->parent_name = parent->name; 1307f3d101b4SDmytro Linkin else 1308f3d101b4SDmytro Linkin nsim_node->parent_name = NULL; 1309f3d101b4SDmytro Linkin return 0; 1310f3d101b4SDmytro Linkin } 1311f3d101b4SDmytro Linkin 1312a7b3527aSOleksandr Mazur static int 1313275b51c2SOleksandr Mazur nsim_dev_devlink_trap_drop_counter_get(struct devlink *devlink, 1314a7b3527aSOleksandr Mazur const struct devlink_trap *trap, 1315a7b3527aSOleksandr Mazur u64 *p_drops) 1316a7b3527aSOleksandr Mazur { 1317a7b3527aSOleksandr Mazur struct nsim_dev *nsim_dev = devlink_priv(devlink); 1318a7b3527aSOleksandr Mazur u64 *cnt; 1319a7b3527aSOleksandr Mazur 1320275b51c2SOleksandr Mazur if (nsim_dev->fail_trap_drop_counter_get) 1321a7b3527aSOleksandr Mazur return -EINVAL; 1322a7b3527aSOleksandr Mazur 1323a7b3527aSOleksandr Mazur cnt = &nsim_dev->trap_data->trap_pkt_cnt; 1324a7b3527aSOleksandr Mazur *p_drops = (*cnt)++; 1325a7b3527aSOleksandr Mazur 1326a7b3527aSOleksandr Mazur return 0; 1327a7b3527aSOleksandr Mazur } 1328a7b3527aSOleksandr Mazur 13298fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 1330160dc373SDmytro Linkin .eswitch_mode_set = nsim_devlink_eswitch_mode_set, 1331160dc373SDmytro Linkin .eswitch_mode_get = nsim_devlink_eswitch_mode_get, 1332cbb58368SJacob Keller .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT | 1333cbb58368SJacob Keller 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, 1404885dfe12SDmytro Linkin nsim_dev_port); 1405885dfe12SDmytro Linkin if (err) 1406885dfe12SDmytro Linkin goto err_nsim_destroy; 1407885dfe12SDmytro Linkin } 1408885dfe12SDmytro Linkin 1409e05b2d14SJiri Pirko devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); 14108320d145SJiri Pirko list_add(&nsim_dev_port->list, &nsim_dev->port_list); 14118320d145SJiri Pirko 14128320d145SJiri Pirko return 0; 14138320d145SJiri Pirko 1414885dfe12SDmytro Linkin err_nsim_destroy: 1415885dfe12SDmytro Linkin nsim_destroy(nsim_dev_port->ns); 1416e05b2d14SJiri Pirko err_port_debugfs_exit: 1417e05b2d14SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 14188320d145SJiri Pirko err_dl_port_unregister: 141976eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14208320d145SJiri Pirko err_port_free: 14218320d145SJiri Pirko kfree(nsim_dev_port); 14228320d145SJiri Pirko return err; 14238320d145SJiri Pirko } 14248320d145SJiri Pirko 1425794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 14268320d145SJiri Pirko { 14278320d145SJiri Pirko struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 14288320d145SJiri Pirko 14298320d145SJiri Pirko list_del(&nsim_dev_port->list); 1430885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 143176eea6c2SJakub Kicinski devl_rate_leaf_destroy(&nsim_dev_port->devlink_port); 1432e05b2d14SJiri Pirko devlink_port_type_clear(devlink_port); 1433e05b2d14SJiri Pirko nsim_destroy(nsim_dev_port->ns); 14348320d145SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 143576eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14368320d145SJiri Pirko kfree(nsim_dev_port); 14378320d145SJiri Pirko } 14388320d145SJiri Pirko 14398320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 14408320d145SJiri Pirko { 14418320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port, *tmp; 14428320d145SJiri Pirko 144376eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 14448320d145SJiri Pirko list_for_each_entry_safe(nsim_dev_port, tmp, 14458320d145SJiri Pirko &nsim_dev->port_list, list) 1446794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 144776eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 14488320d145SJiri Pirko } 14498320d145SJiri Pirko 14507f36a77aSJiri Pirko static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, 14517f36a77aSJiri Pirko unsigned int port_count) 14528320d145SJiri Pirko { 14537f36a77aSJiri Pirko int i, err; 14548320d145SJiri Pirko 14557f36a77aSJiri Pirko for (i = 0; i < port_count; i++) { 145676eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1457814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); 145876eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 14598320d145SJiri Pirko if (err) 14608320d145SJiri Pirko goto err_port_del_all; 14618320d145SJiri Pirko } 14628320d145SJiri Pirko return 0; 14638320d145SJiri Pirko 14648320d145SJiri Pirko err_port_del_all: 14658320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 14668320d145SJiri Pirko return err; 14678320d145SJiri Pirko } 14688320d145SJiri Pirko 146975ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 147075ba029fSJiri Pirko struct netlink_ext_ack *extack) 147175ba029fSJiri Pirko { 147275ba029fSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 147375ba029fSJiri Pirko struct devlink *devlink; 147475ba029fSJiri Pirko int err; 147575ba029fSJiri Pirko 147675ba029fSJiri Pirko devlink = priv_to_devlink(nsim_dev); 147775ba029fSJiri Pirko nsim_dev = devlink_priv(devlink); 147875ba029fSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 147975ba029fSJiri Pirko nsim_dev->fw_update_status = true; 1480cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 148175ba029fSJiri Pirko 148275ba029fSJiri Pirko nsim_devlink_param_load_driverinit_values(devlink); 148375ba029fSJiri Pirko 148475ba029fSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 148575ba029fSJiri Pirko if (err) 1486f57ab5b7SIdo Schimmel return err; 148775ba029fSJiri Pirko 148875ba029fSJiri Pirko err = nsim_dev_traps_init(devlink); 148975ba029fSJiri Pirko if (err) 149075ba029fSJiri Pirko goto err_dummy_region_exit; 149175ba029fSJiri Pirko 1492f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, extack); 1493f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1494f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1495f57ab5b7SIdo Schimmel goto err_traps_exit; 1496f57ab5b7SIdo Schimmel } 1497f57ab5b7SIdo Schimmel 149882c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 149975ba029fSJiri Pirko if (err) 1500f57ab5b7SIdo Schimmel goto err_fib_destroy; 150175ba029fSJiri Pirko 1502a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 150382c93a87SJiri Pirko if (err) 150482c93a87SJiri Pirko goto err_health_exit; 150582c93a87SJiri Pirko 15061a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1507a8700c3dSIdo Schimmel if (err) 1508a8700c3dSIdo Schimmel goto err_psample_exit; 1509a8700c3dSIdo Schimmel 15101a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 15111a6d7ae7SPetr Machata if (err) 15121a6d7ae7SPetr Machata goto err_hwstats_exit; 15131a6d7ae7SPetr Machata 15148526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 15158526ad96STaehee Yoo 0200, 15168526ad96STaehee Yoo nsim_dev->ddir, 15178526ad96STaehee Yoo nsim_dev, 15188526ad96STaehee Yoo &nsim_dev_take_snapshot_fops); 151975ba029fSJiri Pirko return 0; 152075ba029fSJiri Pirko 15211a6d7ae7SPetr Machata err_hwstats_exit: 15221a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1523a8700c3dSIdo Schimmel err_psample_exit: 1524a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 152582c93a87SJiri Pirko err_health_exit: 152682c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1527f57ab5b7SIdo Schimmel err_fib_destroy: 1528f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 152975ba029fSJiri Pirko err_traps_exit: 153075ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 153175ba029fSJiri Pirko err_dummy_region_exit: 153275ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 153375ba029fSJiri Pirko return err; 153475ba029fSJiri Pirko } 153575ba029fSJiri Pirko 1536a66f64b8SJakub Kicinski int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) 15377f36a77aSJiri Pirko { 15387f36a77aSJiri Pirko struct nsim_dev *nsim_dev; 15397f36a77aSJiri Pirko struct devlink *devlink; 15407f36a77aSJiri Pirko int err; 15417f36a77aSJiri Pirko 154226713455SLeon Romanovsky devlink = devlink_alloc_ns(&nsim_dev_devlink_ops, sizeof(*nsim_dev), 1543919d13a7SLeon Romanovsky nsim_bus_dev->initial_net, &nsim_bus_dev->dev); 15447f36a77aSJiri Pirko if (!devlink) 1545bfcccfe7SJakub Kicinski return -ENOMEM; 15467f36a77aSJiri Pirko nsim_dev = devlink_priv(devlink); 15477f36a77aSJiri Pirko nsim_dev->nsim_bus_dev = nsim_bus_dev; 15487f36a77aSJiri Pirko nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 15497f36a77aSJiri Pirko get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 15507f36a77aSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 15517f36a77aSJiri Pirko nsim_dev->fw_update_status = true; 1552cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 15537f36a77aSJiri Pirko nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; 15547f36a77aSJiri Pirko nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; 1555d3cbb907SJiri Pirko spin_lock_init(&nsim_dev->fa_cookie_lock); 15567f36a77aSJiri Pirko 1557bfcccfe7SJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 1558bfcccfe7SJakub Kicinski 15595e388f3dSJakub Kicinski nsim_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 15605e388f3dSJakub Kicinski sizeof(struct nsim_vf_config), 15615e388f3dSJakub Kicinski GFP_KERNEL | __GFP_NOWARN); 15625e388f3dSJakub Kicinski if (!nsim_dev->vfconfigs) { 15635e388f3dSJakub Kicinski err = -ENOMEM; 15645e388f3dSJakub Kicinski goto err_devlink_free; 15655e388f3dSJakub Kicinski } 15665e388f3dSJakub Kicinski 15677f36a77aSJiri Pirko err = nsim_dev_resources_register(devlink); 15687f36a77aSJiri Pirko if (err) 15695e388f3dSJakub Kicinski goto err_vfc_free; 15707f36a77aSJiri Pirko 15717f36a77aSJiri Pirko err = devlink_params_register(devlink, nsim_devlink_params, 15727f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 15737f36a77aSJiri Pirko if (err) 15747f36a77aSJiri Pirko goto err_dl_unregister; 15757f36a77aSJiri Pirko nsim_devlink_set_params_init_values(nsim_dev, devlink); 15767f36a77aSJiri Pirko 15777f36a77aSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 15787f36a77aSJiri Pirko if (err) 15797f36a77aSJiri Pirko goto err_params_unregister; 15807f36a77aSJiri Pirko 15817f36a77aSJiri Pirko err = nsim_dev_traps_init(devlink); 15827f36a77aSJiri Pirko if (err) 15837f36a77aSJiri Pirko goto err_dummy_region_exit; 15847f36a77aSJiri Pirko 15857f36a77aSJiri Pirko err = nsim_dev_debugfs_init(nsim_dev); 15867f36a77aSJiri Pirko if (err) 15877f36a77aSJiri Pirko goto err_traps_exit; 15887f36a77aSJiri Pirko 1589f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, NULL); 1590f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1591f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1592f57ab5b7SIdo Schimmel goto err_debugfs_exit; 1593f57ab5b7SIdo Schimmel } 1594f57ab5b7SIdo Schimmel 159582c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 15967f36a77aSJiri Pirko if (err) 1597f57ab5b7SIdo Schimmel goto err_fib_destroy; 15987f36a77aSJiri Pirko 159982c93a87SJiri Pirko err = nsim_bpf_dev_init(nsim_dev); 160082c93a87SJiri Pirko if (err) 160182c93a87SJiri Pirko goto err_health_exit; 160282c93a87SJiri Pirko 1603a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 16047f36a77aSJiri Pirko if (err) 16057f36a77aSJiri Pirko goto err_bpf_dev_exit; 16067f36a77aSJiri Pirko 16071a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1608a8700c3dSIdo Schimmel if (err) 1609a8700c3dSIdo Schimmel goto err_psample_exit; 1610a8700c3dSIdo Schimmel 16111a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 16121a6d7ae7SPetr Machata if (err) 16131a6d7ae7SPetr Machata goto err_hwstats_exit; 16141a6d7ae7SPetr Machata 1615160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 1616bd032e35SLeon Romanovsky devlink_set_features(devlink, DEVLINK_F_RELOAD); 161771c1b525SLeon Romanovsky devlink_register(devlink); 1618bfcccfe7SJakub Kicinski return 0; 16197f36a77aSJiri Pirko 16201a6d7ae7SPetr Machata err_hwstats_exit: 16211a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1622a8700c3dSIdo Schimmel err_psample_exit: 1623a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 16247f36a77aSJiri Pirko err_bpf_dev_exit: 16257f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 162682c93a87SJiri Pirko err_health_exit: 162782c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1628f57ab5b7SIdo Schimmel err_fib_destroy: 1629f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 16307f36a77aSJiri Pirko err_debugfs_exit: 16317f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16327f36a77aSJiri Pirko err_traps_exit: 16337f36a77aSJiri Pirko nsim_dev_traps_exit(devlink); 16347f36a77aSJiri Pirko err_dummy_region_exit: 16357f36a77aSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 16367f36a77aSJiri Pirko err_params_unregister: 16377f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16387f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 16397f36a77aSJiri Pirko err_dl_unregister: 16404c897cfcSLeon Romanovsky devlink_resources_unregister(devlink); 16415e388f3dSJakub Kicinski err_vfc_free: 16425e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 16437f36a77aSJiri Pirko err_devlink_free: 16447f36a77aSJiri Pirko devlink_free(devlink); 16455e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 1646bfcccfe7SJakub Kicinski return err; 16477f36a77aSJiri Pirko } 16487f36a77aSJiri Pirko 164975ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) 165075ba029fSJiri Pirko { 165175ba029fSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 165275ba029fSJiri Pirko 165375ba029fSJiri Pirko if (devlink_is_reload_failed(devlink)) 165475ba029fSJiri Pirko return; 16558526ad96STaehee Yoo debugfs_remove(nsim_dev->take_snapshot); 165632ac15d8SDmytro Linkin 1657*aff3a925SJakub Kicinski devl_lock(devlink); 16581c401078SJakub Kicinski if (nsim_dev_get_vfs(nsim_dev)) { 16591c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_dev->nsim_bus_dev, 0); 16601c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) 16611c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 16621c401078SJakub Kicinski } 1663*aff3a925SJakub Kicinski devl_unlock(devlink); 166432ac15d8SDmytro Linkin 166575ba029fSJiri Pirko nsim_dev_port_del_all(nsim_dev); 16661a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1667a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 166882c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1669f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 167075ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 167175ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 167275ba029fSJiri Pirko } 167375ba029fSJiri Pirko 1674a66f64b8SJakub Kicinski void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev) 16757f36a77aSJiri Pirko { 1676bfcccfe7SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 16777f36a77aSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 16787f36a77aSJiri Pirko 167971c1b525SLeon Romanovsky devlink_unregister(devlink); 168075ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 168175ba029fSJiri Pirko 16827f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 16837f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16847f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16857f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 16864c897cfcSLeon Romanovsky devlink_resources_unregister(devlink); 16875e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 16887f36a77aSJiri Pirko devlink_free(devlink); 16895e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 16907f36a77aSJiri Pirko } 16917f36a77aSJiri Pirko 1692794b2c05SJiri Pirko static struct nsim_dev_port * 1693814b9ce6SDmytro Linkin __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1694814b9ce6SDmytro Linkin unsigned int port_index) 1695794b2c05SJiri Pirko { 1696794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1697794b2c05SJiri Pirko 1698814b9ce6SDmytro Linkin port_index = nsim_dev_port_index(type, port_index); 1699794b2c05SJiri Pirko list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 1700794b2c05SJiri Pirko if (nsim_dev_port->port_index == port_index) 1701794b2c05SJiri Pirko return nsim_dev_port; 1702794b2c05SJiri Pirko return NULL; 1703794b2c05SJiri Pirko } 1704794b2c05SJiri Pirko 1705a66f64b8SJakub Kicinski int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1706794b2c05SJiri Pirko unsigned int port_index) 1707794b2c05SJiri Pirko { 1708794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1709794b2c05SJiri Pirko int err; 1710794b2c05SJiri Pirko 171176eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1712814b9ce6SDmytro Linkin if (__nsim_dev_port_lookup(nsim_dev, type, port_index)) 1713794b2c05SJiri Pirko err = -EEXIST; 1714794b2c05SJiri Pirko else 1715814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, type, port_index); 171676eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1717794b2c05SJiri Pirko return err; 1718794b2c05SJiri Pirko } 1719794b2c05SJiri Pirko 1720a66f64b8SJakub Kicinski int nsim_drv_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1721794b2c05SJiri Pirko unsigned int port_index) 1722794b2c05SJiri Pirko { 1723794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1724794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1725794b2c05SJiri Pirko int err = 0; 1726794b2c05SJiri Pirko 172776eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1728814b9ce6SDmytro Linkin nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index); 1729794b2c05SJiri Pirko if (!nsim_dev_port) 1730794b2c05SJiri Pirko err = -ENOENT; 1731794b2c05SJiri Pirko else 1732794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 173376eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1734794b2c05SJiri Pirko return err; 1735794b2c05SJiri Pirko } 1736794b2c05SJiri Pirko 17371c401078SJakub Kicinski int nsim_drv_configure_vfs(struct nsim_bus_dev *nsim_bus_dev, 17381c401078SJakub Kicinski unsigned int num_vfs) 17391c401078SJakub Kicinski { 17401c401078SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1741*aff3a925SJakub Kicinski struct devlink *devlink = priv_to_devlink(nsim_dev); 1742047304d0SJakub Kicinski int ret = 0; 17431c401078SJakub Kicinski 1744*aff3a925SJakub Kicinski devl_lock(devlink); 1745047304d0SJakub Kicinski if (nsim_bus_dev->num_vfs == num_vfs) 17461c401078SJakub Kicinski goto exit_unlock; 17471c401078SJakub Kicinski if (nsim_bus_dev->num_vfs && num_vfs) { 17481c401078SJakub Kicinski ret = -EBUSY; 17491c401078SJakub Kicinski goto exit_unlock; 17501c401078SJakub Kicinski } 17511c401078SJakub Kicinski if (nsim_bus_dev->max_vfs < num_vfs) { 17521c401078SJakub Kicinski ret = -ENOMEM; 17531c401078SJakub Kicinski goto exit_unlock; 17541c401078SJakub Kicinski } 17551c401078SJakub Kicinski 17561c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, num_vfs); 17571c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) { 17581c401078SJakub Kicinski if (num_vfs) { 17591c401078SJakub Kicinski ret = nsim_esw_switchdev_enable(nsim_dev, NULL); 17601c401078SJakub Kicinski if (ret) { 17611c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 17621c401078SJakub Kicinski goto exit_unlock; 17631c401078SJakub Kicinski } 17641c401078SJakub Kicinski } else { 17651c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 17661c401078SJakub Kicinski } 17671c401078SJakub Kicinski } 17681c401078SJakub Kicinski 17691c401078SJakub Kicinski exit_unlock: 1770*aff3a925SJakub Kicinski devl_unlock(devlink); 17711c401078SJakub Kicinski 17721c401078SJakub Kicinski return ret; 17731c401078SJakub Kicinski } 17741c401078SJakub Kicinski 1775d514f41eSJiri Pirko int nsim_dev_init(void) 1776d514f41eSJiri Pirko { 1777ab1d0cc0SJiri Pirko nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 177834611e69Skbuild test robot return PTR_ERR_OR_ZERO(nsim_dev_ddir); 1779d514f41eSJiri Pirko } 1780d514f41eSJiri Pirko 1781d514f41eSJiri Pirko void nsim_dev_exit(void) 1782d514f41eSJiri Pirko { 1783d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev_ddir); 1784d514f41eSJiri Pirko } 1785