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() && 625e388f3dSJakub Kicinski !lockdep_is_held(&nsim_dev->vfs_lock)); 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; 278a3353ec3SJakub Kicinski mutex_lock(&nsim_dev->vfs_lock); 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 } 288a3353ec3SJakub Kicinski mutex_unlock(&nsim_dev->vfs_lock); 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); 342ba064e4cSJakub Kicinski debugfs_create_file("max_vfs", 0600, nsim_dev->ddir, 3435e388f3dSJakub Kicinski nsim_dev, &nsim_dev_max_vfs_fops); 344ba064e4cSJakub Kicinski 345885226f5SDmytro Linkin nsim_dev->nodes_ddir = debugfs_create_dir("rate_nodes", nsim_dev->ddir); 346f3d101b4SDmytro Linkin if (IS_ERR(nsim_dev->nodes_ddir)) { 347f3d101b4SDmytro Linkin err = PTR_ERR(nsim_dev->nodes_ddir); 348f3d101b4SDmytro Linkin goto err_out; 349f3d101b4SDmytro Linkin } 350275b51c2SOleksandr Mazur debugfs_create_bool("fail_trap_drop_counter_get", 0600, 351a7b3527aSOleksandr Mazur nsim_dev->ddir, 352275b51c2SOleksandr Mazur &nsim_dev->fail_trap_drop_counter_get); 353424be63aSJakub Kicinski nsim_udp_tunnels_debugfs_create(nsim_dev); 354d514f41eSJiri Pirko return 0; 355f3d101b4SDmytro Linkin 356f3d101b4SDmytro Linkin err_out: 357f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ports_ddir); 358f3d101b4SDmytro Linkin debugfs_remove_recursive(nsim_dev->ddir); 359f3d101b4SDmytro Linkin return err; 360d514f41eSJiri Pirko } 361d514f41eSJiri Pirko 362d514f41eSJiri Pirko static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev) 363d514f41eSJiri Pirko { 364885226f5SDmytro Linkin debugfs_remove_recursive(nsim_dev->nodes_ddir); 365ab1d0cc0SJiri Pirko debugfs_remove_recursive(nsim_dev->ports_ddir); 366d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev->ddir); 367d514f41eSJiri Pirko } 368d514f41eSJiri Pirko 369f3d101b4SDmytro Linkin static ssize_t nsim_dev_rate_parent_read(struct file *file, 370f3d101b4SDmytro Linkin char __user *data, 371f3d101b4SDmytro Linkin size_t count, loff_t *ppos) 372f3d101b4SDmytro Linkin { 373f3d101b4SDmytro Linkin char **name_ptr = file->private_data; 374f3d101b4SDmytro Linkin size_t len; 375f3d101b4SDmytro Linkin 376f3d101b4SDmytro Linkin if (!*name_ptr) 377f3d101b4SDmytro Linkin return 0; 378f3d101b4SDmytro Linkin 379f3d101b4SDmytro Linkin len = strlen(*name_ptr); 380f3d101b4SDmytro Linkin return simple_read_from_buffer(data, count, ppos, *name_ptr, len); 381f3d101b4SDmytro Linkin } 382f3d101b4SDmytro Linkin 383f3d101b4SDmytro Linkin static const struct file_operations nsim_dev_rate_parent_fops = { 384f3d101b4SDmytro Linkin .open = simple_open, 385f3d101b4SDmytro Linkin .read = nsim_dev_rate_parent_read, 386f3d101b4SDmytro Linkin .llseek = generic_file_llseek, 387f3d101b4SDmytro Linkin .owner = THIS_MODULE, 388f3d101b4SDmytro Linkin }; 389f3d101b4SDmytro Linkin 3908320d145SJiri Pirko static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev, 3918320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port) 3928320d145SJiri Pirko { 393605c4f8fSDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 394605c4f8fSDmytro Linkin unsigned int port_index = nsim_dev_port->port_index; 3958320d145SJiri Pirko char port_ddir_name[16]; 3968320d145SJiri Pirko char dev_link_name[32]; 3978320d145SJiri Pirko 398605c4f8fSDmytro Linkin sprintf(port_ddir_name, "%u", port_index); 3998320d145SJiri Pirko nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name, 4008320d145SJiri Pirko nsim_dev->ports_ddir); 4016556ff32STaehee Yoo if (IS_ERR(nsim_dev_port->ddir)) 4026556ff32STaehee Yoo return PTR_ERR(nsim_dev_port->ddir); 4038320d145SJiri Pirko 404605c4f8fSDmytro Linkin sprintf(dev_link_name, "../../../" DRV_NAME "%u", nsim_bus_dev->dev.id); 405605c4f8fSDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 406605c4f8fSDmytro Linkin unsigned int vf_id = nsim_dev_port_index_to_vf_index(port_index); 407605c4f8fSDmytro Linkin 408605c4f8fSDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_dev_port->ddir, 4095e388f3dSJakub Kicinski &nsim_dev->vfconfigs[vf_id].min_tx_rate); 410605c4f8fSDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_dev_port->ddir, 4115e388f3dSJakub Kicinski &nsim_dev->vfconfigs[vf_id].max_tx_rate); 412f3d101b4SDmytro Linkin nsim_dev_port->rate_parent = debugfs_create_file("rate_parent", 413f3d101b4SDmytro Linkin 0400, 414f3d101b4SDmytro Linkin nsim_dev_port->ddir, 415f3d101b4SDmytro Linkin &nsim_dev_port->parent_name, 416f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 417605c4f8fSDmytro Linkin } 4188320d145SJiri Pirko debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name); 4198320d145SJiri Pirko 4208320d145SJiri Pirko return 0; 4218320d145SJiri Pirko } 4228320d145SJiri Pirko 4238320d145SJiri Pirko static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port) 4248320d145SJiri Pirko { 4258320d145SJiri Pirko debugfs_remove_recursive(nsim_dev_port->ddir); 4268320d145SJiri Pirko } 4278320d145SJiri Pirko 4288fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink) 4298fb4bc6fSJiri Pirko { 4308fb4bc6fSJiri Pirko struct devlink_resource_size_params params = { 4318fb4bc6fSJiri Pirko .size_max = (u64)-1, 4328fb4bc6fSJiri Pirko .size_granularity = 1, 4338fb4bc6fSJiri Pirko .unit = DEVLINK_RESOURCE_UNIT_ENTRY 4348fb4bc6fSJiri Pirko }; 4358fb4bc6fSJiri Pirko int err; 4368fb4bc6fSJiri Pirko 4378fb4bc6fSJiri Pirko /* Resources for IPv4 */ 4388fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv4", (u64)-1, 4398fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, 4408fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 4418fb4bc6fSJiri Pirko ¶ms); 4428fb4bc6fSJiri Pirko if (err) { 4438fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 top resource\n"); 4448fb4bc6fSJiri Pirko goto out; 4458fb4bc6fSJiri Pirko } 4468fb4bc6fSJiri Pirko 447a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib", (u64)-1, 4488fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 4498fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 4508fb4bc6fSJiri Pirko if (err) { 4518fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB resource\n"); 4528fb4bc6fSJiri Pirko return err; 4538fb4bc6fSJiri Pirko } 4548fb4bc6fSJiri Pirko 455a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", (u64)-1, 4568fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 4578fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 4588fb4bc6fSJiri Pirko if (err) { 4598fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB rules resource\n"); 4608fb4bc6fSJiri Pirko return err; 4618fb4bc6fSJiri Pirko } 4628fb4bc6fSJiri Pirko 4638fb4bc6fSJiri Pirko /* Resources for IPv6 */ 4648fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv6", (u64)-1, 4658fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, 4668fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 4678fb4bc6fSJiri Pirko ¶ms); 4688fb4bc6fSJiri Pirko if (err) { 4698fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 top resource\n"); 4708fb4bc6fSJiri Pirko goto out; 4718fb4bc6fSJiri Pirko } 4728fb4bc6fSJiri Pirko 473a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib", (u64)-1, 4748fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 4758fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 4768fb4bc6fSJiri Pirko if (err) { 4778fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB resource\n"); 4788fb4bc6fSJiri Pirko return err; 4798fb4bc6fSJiri Pirko } 4808fb4bc6fSJiri Pirko 481a5facc4cSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", (u64)-1, 4828fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 4838fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 4848fb4bc6fSJiri Pirko if (err) { 4858fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB rules resource\n"); 4868fb4bc6fSJiri Pirko return err; 4878fb4bc6fSJiri Pirko } 4888fb4bc6fSJiri Pirko 48935266255SIdo Schimmel /* Resources for nexthops */ 49035266255SIdo Schimmel err = devlink_resource_register(devlink, "nexthops", (u64)-1, 49135266255SIdo Schimmel NSIM_RESOURCE_NEXTHOPS, 49235266255SIdo Schimmel DEVLINK_RESOURCE_ID_PARENT_TOP, 49335266255SIdo Schimmel ¶ms); 49435266255SIdo Schimmel 4958fb4bc6fSJiri Pirko out: 4968fb4bc6fSJiri Pirko return err; 4978fb4bc6fSJiri Pirko } 4988fb4bc6fSJiri Pirko 499150e8f8aSJiri Pirko enum nsim_devlink_param_id { 500150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 501150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 502150e8f8aSJiri Pirko }; 503150e8f8aSJiri Pirko 504150e8f8aSJiri Pirko static const struct devlink_param nsim_devlink_params[] = { 505150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC(MAX_MACS, 506150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 507150e8f8aSJiri Pirko NULL, NULL, NULL), 508150e8f8aSJiri Pirko DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1, 509150e8f8aSJiri Pirko "test1", DEVLINK_PARAM_TYPE_BOOL, 510150e8f8aSJiri Pirko BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), 511150e8f8aSJiri Pirko NULL, NULL, NULL), 512150e8f8aSJiri Pirko }; 513150e8f8aSJiri Pirko 514150e8f8aSJiri Pirko static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev, 515150e8f8aSJiri Pirko struct devlink *devlink) 516150e8f8aSJiri Pirko { 517150e8f8aSJiri Pirko union devlink_param_value value; 518150e8f8aSJiri Pirko 519150e8f8aSJiri Pirko value.vu32 = nsim_dev->max_macs; 520150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 521150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 522150e8f8aSJiri Pirko value); 523150e8f8aSJiri Pirko value.vbool = nsim_dev->test1; 524150e8f8aSJiri Pirko devlink_param_driverinit_value_set(devlink, 525150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 526150e8f8aSJiri Pirko value); 527150e8f8aSJiri Pirko } 528150e8f8aSJiri Pirko 529150e8f8aSJiri Pirko static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink) 530150e8f8aSJiri Pirko { 531150e8f8aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 532150e8f8aSJiri Pirko union devlink_param_value saved_value; 533150e8f8aSJiri Pirko int err; 534150e8f8aSJiri Pirko 535150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 536150e8f8aSJiri Pirko DEVLINK_PARAM_GENERIC_ID_MAX_MACS, 537150e8f8aSJiri Pirko &saved_value); 538150e8f8aSJiri Pirko if (!err) 539150e8f8aSJiri Pirko nsim_dev->max_macs = saved_value.vu32; 540150e8f8aSJiri Pirko err = devlink_param_driverinit_value_get(devlink, 541150e8f8aSJiri Pirko NSIM_DEVLINK_PARAM_ID_TEST1, 542150e8f8aSJiri Pirko &saved_value); 543150e8f8aSJiri Pirko if (!err) 544150e8f8aSJiri Pirko nsim_dev->test1 = saved_value.vbool; 545150e8f8aSJiri Pirko } 546150e8f8aSJiri Pirko 5474418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX 16 5484418f862SJiri Pirko 549e8937681SJacob Keller static const struct devlink_region_ops dummy_region_ops = { 550e8937681SJacob Keller .name = "dummy", 551a0a09f6bSJacob Keller .destructor = &kfree, 5523fe0fd53SJacob Keller .snapshot = nsim_dev_take_snapshot, 553e8937681SJacob Keller }; 554e8937681SJacob Keller 5554418f862SJiri Pirko static int nsim_dev_dummy_region_init(struct nsim_dev *nsim_dev, 5564418f862SJiri Pirko struct devlink *devlink) 5574418f862SJiri Pirko { 5584418f862SJiri Pirko nsim_dev->dummy_region = 559e8937681SJacob Keller devlink_region_create(devlink, &dummy_region_ops, 5604418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX, 5614418f862SJiri Pirko NSIM_DEV_DUMMY_REGION_SIZE); 5624418f862SJiri Pirko return PTR_ERR_OR_ZERO(nsim_dev->dummy_region); 5634418f862SJiri Pirko } 5644418f862SJiri Pirko 5654418f862SJiri Pirko static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev) 5664418f862SJiri Pirko { 5674418f862SJiri Pirko devlink_region_destroy(nsim_dev->dummy_region); 5684418f862SJiri Pirko } 5694418f862SJiri Pirko 570160dc373SDmytro Linkin static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port); 5711c401078SJakub Kicinski 5721c401078SJakub Kicinski static int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, 5731c401078SJakub Kicinski struct netlink_ext_ack *extack) 574160dc373SDmytro Linkin { 575885226f5SDmytro Linkin struct devlink *devlink = priv_to_devlink(nsim_dev); 576160dc373SDmytro Linkin struct nsim_dev_port *nsim_dev_port, *tmp; 577160dc373SDmytro Linkin 578885226f5SDmytro Linkin devlink_rate_nodes_destroy(devlink); 579*76eea6c2SJakub Kicinski devl_lock(devlink); 580160dc373SDmytro Linkin list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) 581160dc373SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 582160dc373SDmytro Linkin __nsim_dev_port_del(nsim_dev_port); 583*76eea6c2SJakub Kicinski devl_unlock(devlink); 584160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 585160dc373SDmytro Linkin return 0; 586160dc373SDmytro Linkin } 587160dc373SDmytro Linkin 5881c401078SJakub Kicinski static int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev, 5891c401078SJakub Kicinski struct netlink_ext_ack *extack) 590160dc373SDmytro Linkin { 591160dc373SDmytro Linkin struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 592160dc373SDmytro Linkin int i, err; 593160dc373SDmytro Linkin 5945e388f3dSJakub Kicinski for (i = 0; i < nsim_dev_get_vfs(nsim_dev); i++) { 595a66f64b8SJakub Kicinski err = nsim_drv_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i); 596160dc373SDmytro Linkin if (err) { 597160dc373SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports"); 598160dc373SDmytro Linkin pr_err("Failed to initialize VF id=%d. %d.\n", i, err); 599160dc373SDmytro Linkin goto err_port_add_vfs; 600160dc373SDmytro Linkin } 601160dc373SDmytro Linkin } 602160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 603160dc373SDmytro Linkin return 0; 604160dc373SDmytro Linkin 605160dc373SDmytro Linkin err_port_add_vfs: 606160dc373SDmytro Linkin for (i--; i >= 0; i--) 607a66f64b8SJakub Kicinski nsim_drv_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i); 608160dc373SDmytro Linkin return err; 609160dc373SDmytro Linkin } 610160dc373SDmytro Linkin 611160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, 612160dc373SDmytro Linkin struct netlink_ext_ack *extack) 613160dc373SDmytro Linkin { 614160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 615160dc373SDmytro Linkin int err = 0; 616160dc373SDmytro Linkin 6175e388f3dSJakub Kicinski mutex_lock(&nsim_dev->vfs_lock); 618160dc373SDmytro Linkin if (mode == nsim_dev->esw_mode) 619160dc373SDmytro Linkin goto unlock; 620160dc373SDmytro Linkin 621160dc373SDmytro Linkin if (mode == DEVLINK_ESWITCH_MODE_LEGACY) 622160dc373SDmytro Linkin err = nsim_esw_legacy_enable(nsim_dev, extack); 623160dc373SDmytro Linkin else if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) 624160dc373SDmytro Linkin err = nsim_esw_switchdev_enable(nsim_dev, extack); 625160dc373SDmytro Linkin else 626160dc373SDmytro Linkin err = -EINVAL; 627160dc373SDmytro Linkin 628160dc373SDmytro Linkin unlock: 6295e388f3dSJakub Kicinski mutex_unlock(&nsim_dev->vfs_lock); 630160dc373SDmytro Linkin return err; 631160dc373SDmytro Linkin } 632160dc373SDmytro Linkin 633160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) 634160dc373SDmytro Linkin { 635160dc373SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(devlink); 636160dc373SDmytro Linkin 637160dc373SDmytro Linkin *mode = nsim_dev->esw_mode; 638160dc373SDmytro Linkin return 0; 639160dc373SDmytro Linkin } 640160dc373SDmytro Linkin 641da58f90fSIdo Schimmel struct nsim_trap_item { 642da58f90fSIdo Schimmel void *trap_ctx; 643da58f90fSIdo Schimmel enum devlink_trap_action action; 644da58f90fSIdo Schimmel }; 645da58f90fSIdo Schimmel 646da58f90fSIdo Schimmel struct nsim_trap_data { 647da58f90fSIdo Schimmel struct delayed_work trap_report_dw; 648da58f90fSIdo Schimmel struct nsim_trap_item *trap_items_arr; 649ad188458SIdo Schimmel u64 *trap_policers_cnt_arr; 650a7b3527aSOleksandr Mazur u64 trap_pkt_cnt; 651da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 652da58f90fSIdo Schimmel spinlock_t trap_lock; /* Protects trap_items_arr */ 653da58f90fSIdo Schimmel }; 654da58f90fSIdo Schimmel 6559e087457SIdo Schimmel /* All driver-specific traps must be documented in 65604e4272cSJacob Keller * Documentation/networking/devlink/netdevsim.rst 6579e087457SIdo Schimmel */ 658da58f90fSIdo Schimmel enum { 659da58f90fSIdo Schimmel NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX, 660da58f90fSIdo Schimmel NSIM_TRAP_ID_FID_MISS, 661da58f90fSIdo Schimmel }; 662da58f90fSIdo Schimmel 663da58f90fSIdo Schimmel #define NSIM_TRAP_NAME_FID_MISS "fid_miss" 664da58f90fSIdo Schimmel 665da58f90fSIdo Schimmel #define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT 666da58f90fSIdo Schimmel 667da58f90fSIdo Schimmel #define NSIM_TRAP_DROP(_id, _group_id) \ 668da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 669107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 670da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 671d3cbb907SJiri Pirko #define NSIM_TRAP_DROP_EXT(_id, _group_id, _metadata) \ 672d3cbb907SJiri Pirko DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ 673107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 674d3cbb907SJiri Pirko NSIM_TRAP_METADATA | (_metadata)) 675da58f90fSIdo Schimmel #define NSIM_TRAP_EXCEPTION(_id, _group_id) \ 676da58f90fSIdo Schimmel DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ 677107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 678da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 67918979367SIdo Schimmel #define NSIM_TRAP_CONTROL(_id, _group_id, _action) \ 68018979367SIdo Schimmel DEVLINK_TRAP_GENERIC(CONTROL, _action, _id, \ 68118979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 68218979367SIdo Schimmel NSIM_TRAP_METADATA) 683da58f90fSIdo Schimmel #define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id) \ 684da58f90fSIdo Schimmel DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id, \ 685da58f90fSIdo Schimmel NSIM_TRAP_NAME_##_id, \ 686107f1678SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ 687da58f90fSIdo Schimmel NSIM_TRAP_METADATA) 688da58f90fSIdo Schimmel 689ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_RATE 1 690ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_RATE 8000 691ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_BURST 8 692ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_BURST 65536 693ad188458SIdo Schimmel 694ad188458SIdo Schimmel #define NSIM_TRAP_POLICER(_id, _rate, _burst) \ 695ad188458SIdo Schimmel DEVLINK_TRAP_POLICER(_id, _rate, _burst, \ 696ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_RATE, \ 697ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_RATE, \ 698ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MAX_BURST, \ 699ad188458SIdo Schimmel NSIM_DEV_TRAP_POLICER_MIN_BURST) 700ad188458SIdo Schimmel 701ad188458SIdo Schimmel static const struct devlink_trap_policer nsim_trap_policers_arr[] = { 702ad188458SIdo Schimmel NSIM_TRAP_POLICER(1, 1000, 128), 703ad188458SIdo Schimmel NSIM_TRAP_POLICER(2, 2000, 256), 704ad188458SIdo Schimmel NSIM_TRAP_POLICER(3, 3000, 512), 705ad188458SIdo Schimmel }; 706ad188458SIdo Schimmel 707b29545d8SIdo Schimmel static const struct devlink_trap_group nsim_trap_groups_arr[] = { 708f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), 709f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1), 71085176f19SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1), 711f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 2), 712f9f54392SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 3), 71318979367SIdo Schimmel DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 3), 714b29545d8SIdo Schimmel }; 715b29545d8SIdo Schimmel 716da58f90fSIdo Schimmel static const struct devlink_trap nsim_traps_arr[] = { 717da58f90fSIdo Schimmel NSIM_TRAP_DROP(SMAC_MC, L2_DROPS), 718da58f90fSIdo Schimmel NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), 719da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), 720da58f90fSIdo Schimmel NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), 721da58f90fSIdo Schimmel NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), 722da58f90fSIdo Schimmel NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), 723da58f90fSIdo Schimmel NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS), 724da58f90fSIdo Schimmel NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), 72585176f19SIdo Schimmel NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS), 726da58f90fSIdo Schimmel NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS), 727d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS, 728d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 729d3cbb907SJiri Pirko NSIM_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS, 730d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE), 73118979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR), 73218979367SIdo Schimmel NSIM_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, TRAP), 733da58f90fSIdo Schimmel }; 734da58f90fSIdo Schimmel 735da58f90fSIdo Schimmel #define NSIM_TRAP_L4_DATA_LEN 100 736da58f90fSIdo Schimmel 737da58f90fSIdo Schimmel static struct sk_buff *nsim_dev_trap_skb_build(void) 738da58f90fSIdo Schimmel { 739da58f90fSIdo Schimmel int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN; 740da58f90fSIdo Schimmel struct sk_buff *skb; 741da58f90fSIdo Schimmel struct udphdr *udph; 742da58f90fSIdo Schimmel struct ethhdr *eth; 743da58f90fSIdo Schimmel struct iphdr *iph; 744da58f90fSIdo Schimmel 745da58f90fSIdo Schimmel skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); 746da58f90fSIdo Schimmel if (!skb) 747da58f90fSIdo Schimmel return NULL; 748da58f90fSIdo Schimmel tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len; 749da58f90fSIdo Schimmel 75058a406deSIdo Schimmel skb_reset_mac_header(skb); 751da58f90fSIdo Schimmel eth = skb_put(skb, sizeof(struct ethhdr)); 752da58f90fSIdo Schimmel eth_random_addr(eth->h_dest); 753da58f90fSIdo Schimmel eth_random_addr(eth->h_source); 754da58f90fSIdo Schimmel eth->h_proto = htons(ETH_P_IP); 755da58f90fSIdo Schimmel skb->protocol = htons(ETH_P_IP); 756da58f90fSIdo Schimmel 75758a406deSIdo Schimmel skb_set_network_header(skb, skb->len); 758da58f90fSIdo Schimmel iph = skb_put(skb, sizeof(struct iphdr)); 759da58f90fSIdo Schimmel iph->protocol = IPPROTO_UDP; 760da58f90fSIdo Schimmel iph->saddr = in_aton("192.0.2.1"); 761da58f90fSIdo Schimmel iph->daddr = in_aton("198.51.100.1"); 762da58f90fSIdo Schimmel iph->version = 0x4; 763da58f90fSIdo Schimmel iph->frag_off = 0; 764da58f90fSIdo Schimmel iph->ihl = 0x5; 765da58f90fSIdo Schimmel iph->tot_len = htons(tot_len); 766da58f90fSIdo Schimmel iph->ttl = 100; 767d9bd6d27SYueHaibing iph->check = 0; 768d9bd6d27SYueHaibing iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 769da58f90fSIdo Schimmel 77058a406deSIdo Schimmel skb_set_transport_header(skb, skb->len); 771da58f90fSIdo Schimmel udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len); 772da58f90fSIdo Schimmel get_random_bytes(&udph->source, sizeof(u16)); 773da58f90fSIdo Schimmel get_random_bytes(&udph->dest, sizeof(u16)); 774da58f90fSIdo Schimmel udph->len = htons(sizeof(struct udphdr) + data_len); 775da58f90fSIdo Schimmel 776da58f90fSIdo Schimmel return skb; 777da58f90fSIdo Schimmel } 778da58f90fSIdo Schimmel 779da58f90fSIdo Schimmel static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port) 780da58f90fSIdo Schimmel { 781da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 782da58f90fSIdo Schimmel struct devlink *devlink = priv_to_devlink(nsim_dev); 783da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 784da58f90fSIdo Schimmel int i; 785da58f90fSIdo Schimmel 786da58f90fSIdo Schimmel nsim_trap_data = nsim_dev->trap_data; 787da58f90fSIdo Schimmel 788da58f90fSIdo Schimmel spin_lock(&nsim_trap_data->trap_lock); 789da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 790d3cbb907SJiri Pirko struct flow_action_cookie *fa_cookie = NULL; 791da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 792da58f90fSIdo Schimmel struct sk_buff *skb; 793d3cbb907SJiri Pirko bool has_fa_cookie; 794d3cbb907SJiri Pirko 795d3cbb907SJiri Pirko has_fa_cookie = nsim_traps_arr[i].metadata_cap & 796d3cbb907SJiri Pirko DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE; 797da58f90fSIdo Schimmel 798da58f90fSIdo Schimmel nsim_trap_item = &nsim_trap_data->trap_items_arr[i]; 799da58f90fSIdo Schimmel if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP) 800da58f90fSIdo Schimmel continue; 801da58f90fSIdo Schimmel 802da58f90fSIdo Schimmel skb = nsim_dev_trap_skb_build(); 803da58f90fSIdo Schimmel if (!skb) 804da58f90fSIdo Schimmel continue; 805da58f90fSIdo Schimmel skb->dev = nsim_dev_port->ns->netdev; 806da58f90fSIdo Schimmel 807da58f90fSIdo Schimmel /* Trapped packets are usually passed to devlink in softIRQ, 808da58f90fSIdo Schimmel * but in this case they are generated in a workqueue. Disable 809da58f90fSIdo Schimmel * softIRQs to prevent lockdep from complaining about 810da58f90fSIdo Schimmel * "incosistent lock state". 811da58f90fSIdo Schimmel */ 812d3cbb907SJiri Pirko 813d3cbb907SJiri Pirko spin_lock_bh(&nsim_dev->fa_cookie_lock); 814d3cbb907SJiri Pirko fa_cookie = has_fa_cookie ? nsim_dev->fa_cookie : NULL; 815da58f90fSIdo Schimmel devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx, 816d3cbb907SJiri Pirko &nsim_dev_port->devlink_port, fa_cookie); 817d3cbb907SJiri Pirko spin_unlock_bh(&nsim_dev->fa_cookie_lock); 818da58f90fSIdo Schimmel consume_skb(skb); 819da58f90fSIdo Schimmel } 820da58f90fSIdo Schimmel spin_unlock(&nsim_trap_data->trap_lock); 821da58f90fSIdo Schimmel } 822da58f90fSIdo Schimmel 823da58f90fSIdo Schimmel #define NSIM_TRAP_REPORT_INTERVAL_MS 100 824da58f90fSIdo Schimmel 825da58f90fSIdo Schimmel static void nsim_dev_trap_report_work(struct work_struct *work) 826da58f90fSIdo Schimmel { 827da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 828da58f90fSIdo Schimmel struct nsim_dev_port *nsim_dev_port; 829da58f90fSIdo Schimmel struct nsim_dev *nsim_dev; 830da58f90fSIdo Schimmel 831da58f90fSIdo Schimmel nsim_trap_data = container_of(work, struct nsim_trap_data, 832da58f90fSIdo Schimmel trap_report_dw.work); 833da58f90fSIdo Schimmel nsim_dev = nsim_trap_data->nsim_dev; 834da58f90fSIdo Schimmel 835da58f90fSIdo Schimmel /* For each running port and enabled packet trap, generate a UDP 836da58f90fSIdo Schimmel * packet with a random 5-tuple and report it. 837da58f90fSIdo Schimmel */ 838*76eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 839da58f90fSIdo Schimmel list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) { 840da58f90fSIdo Schimmel if (!netif_running(nsim_dev_port->ns->netdev)) 841da58f90fSIdo Schimmel continue; 842da58f90fSIdo Schimmel 843da58f90fSIdo Schimmel nsim_dev_trap_report(nsim_dev_port); 844da58f90fSIdo Schimmel } 845*76eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 846da58f90fSIdo Schimmel 847da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 848da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 849da58f90fSIdo Schimmel } 850da58f90fSIdo Schimmel 851da58f90fSIdo Schimmel static int nsim_dev_traps_init(struct devlink *devlink) 852da58f90fSIdo Schimmel { 853ad188458SIdo Schimmel size_t policers_count = ARRAY_SIZE(nsim_trap_policers_arr); 854da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 855da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data; 856da58f90fSIdo Schimmel int err; 857da58f90fSIdo Schimmel 858da58f90fSIdo Schimmel nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL); 859da58f90fSIdo Schimmel if (!nsim_trap_data) 860da58f90fSIdo Schimmel return -ENOMEM; 861da58f90fSIdo Schimmel 862da58f90fSIdo Schimmel nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr), 863da58f90fSIdo Schimmel sizeof(struct nsim_trap_item), 864da58f90fSIdo Schimmel GFP_KERNEL); 865da58f90fSIdo Schimmel if (!nsim_trap_data->trap_items_arr) { 866da58f90fSIdo Schimmel err = -ENOMEM; 867da58f90fSIdo Schimmel goto err_trap_data_free; 868da58f90fSIdo Schimmel } 869da58f90fSIdo Schimmel 870ad188458SIdo Schimmel nsim_trap_data->trap_policers_cnt_arr = kcalloc(policers_count, 871ad188458SIdo Schimmel sizeof(u64), 872ad188458SIdo Schimmel GFP_KERNEL); 873ad188458SIdo Schimmel if (!nsim_trap_data->trap_policers_cnt_arr) { 874ad188458SIdo Schimmel err = -ENOMEM; 875ad188458SIdo Schimmel goto err_trap_items_free; 876ad188458SIdo Schimmel } 877ad188458SIdo Schimmel 878da58f90fSIdo Schimmel /* The lock is used to protect the action state of the registered 879da58f90fSIdo Schimmel * traps. The value is written by user and read in delayed work when 880da58f90fSIdo Schimmel * iterating over all the traps. 881da58f90fSIdo Schimmel */ 882da58f90fSIdo Schimmel spin_lock_init(&nsim_trap_data->trap_lock); 883da58f90fSIdo Schimmel nsim_trap_data->nsim_dev = nsim_dev; 884da58f90fSIdo Schimmel nsim_dev->trap_data = nsim_trap_data; 885da58f90fSIdo Schimmel 886ad188458SIdo Schimmel err = devlink_trap_policers_register(devlink, nsim_trap_policers_arr, 887ad188458SIdo Schimmel policers_count); 888ad188458SIdo Schimmel if (err) 889ad188458SIdo Schimmel goto err_trap_policers_cnt_free; 890ad188458SIdo Schimmel 891b29545d8SIdo Schimmel err = devlink_trap_groups_register(devlink, nsim_trap_groups_arr, 892b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 893b29545d8SIdo Schimmel if (err) 894ad188458SIdo Schimmel goto err_trap_policers_unregister; 895b29545d8SIdo Schimmel 896da58f90fSIdo Schimmel err = devlink_traps_register(devlink, nsim_traps_arr, 897da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr), NULL); 898da58f90fSIdo Schimmel if (err) 899b29545d8SIdo Schimmel goto err_trap_groups_unregister; 900da58f90fSIdo Schimmel 901da58f90fSIdo Schimmel INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw, 902da58f90fSIdo Schimmel nsim_dev_trap_report_work); 903da58f90fSIdo Schimmel schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 904da58f90fSIdo Schimmel msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS)); 905da58f90fSIdo Schimmel 906da58f90fSIdo Schimmel return 0; 907da58f90fSIdo Schimmel 908b29545d8SIdo Schimmel err_trap_groups_unregister: 909b29545d8SIdo Schimmel devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, 910b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 911ad188458SIdo Schimmel err_trap_policers_unregister: 912ad188458SIdo Schimmel devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, 913ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 914ad188458SIdo Schimmel err_trap_policers_cnt_free: 915ad188458SIdo Schimmel kfree(nsim_trap_data->trap_policers_cnt_arr); 916da58f90fSIdo Schimmel err_trap_items_free: 917da58f90fSIdo Schimmel kfree(nsim_trap_data->trap_items_arr); 918da58f90fSIdo Schimmel err_trap_data_free: 919da58f90fSIdo Schimmel kfree(nsim_trap_data); 920da58f90fSIdo Schimmel return err; 921da58f90fSIdo Schimmel } 922da58f90fSIdo Schimmel 923da58f90fSIdo Schimmel static void nsim_dev_traps_exit(struct devlink *devlink) 924da58f90fSIdo Schimmel { 925da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 926da58f90fSIdo Schimmel 927*76eea6c2SJakub Kicinski /* caution, trap work takes devlink lock */ 928da58f90fSIdo Schimmel cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw); 929da58f90fSIdo Schimmel devlink_traps_unregister(devlink, nsim_traps_arr, 930da58f90fSIdo Schimmel ARRAY_SIZE(nsim_traps_arr)); 931b29545d8SIdo Schimmel devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr, 932b29545d8SIdo Schimmel ARRAY_SIZE(nsim_trap_groups_arr)); 933ad188458SIdo Schimmel devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr, 934ad188458SIdo Schimmel ARRAY_SIZE(nsim_trap_policers_arr)); 935ad188458SIdo Schimmel kfree(nsim_dev->trap_data->trap_policers_cnt_arr); 936da58f90fSIdo Schimmel kfree(nsim_dev->trap_data->trap_items_arr); 937da58f90fSIdo Schimmel kfree(nsim_dev->trap_data); 938da58f90fSIdo Schimmel } 939da58f90fSIdo Schimmel 94075ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 94175ba029fSJiri Pirko struct netlink_ext_ack *extack); 94275ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); 94375ba029fSJiri Pirko 944070c63f2SJiri Pirko static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, 945dc64cc7cSMoshe Shemesh enum devlink_reload_action action, enum devlink_reload_limit limit, 946dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 94797691069SJiri Pirko { 94875ba029fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 94923809a72SLeon Romanovsky struct nsim_bus_dev *nsim_bus_dev; 95023809a72SLeon Romanovsky 95123809a72SLeon Romanovsky nsim_bus_dev = nsim_dev->nsim_bus_dev; 95223809a72SLeon Romanovsky if (!mutex_trylock(&nsim_bus_dev->nsim_bus_reload_lock)) 95323809a72SLeon Romanovsky return -EOPNOTSUPP; 95475ba029fSJiri Pirko 955155ddfc5SJiri Pirko if (nsim_dev->dont_allow_reload) { 956155ddfc5SJiri Pirko /* For testing purposes, user set debugfs dont_allow_reload 957155ddfc5SJiri Pirko * value to true. So forbid it. 958155ddfc5SJiri Pirko */ 959f9867b51SColin Ian King NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); 96023809a72SLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 961155ddfc5SJiri Pirko return -EOPNOTSUPP; 962155ddfc5SJiri Pirko } 9635c0418edSLeon Romanovsky nsim_bus_dev->in_reload = true; 964155ddfc5SJiri Pirko 96575ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 96623809a72SLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 96797691069SJiri Pirko return 0; 96897691069SJiri Pirko } 96997691069SJiri Pirko 970ccdf0721SMoshe Shemesh static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action, 971dc64cc7cSMoshe Shemesh enum devlink_reload_limit limit, u32 *actions_performed, 972dc64cc7cSMoshe Shemesh struct netlink_ext_ack *extack) 9738fb4bc6fSJiri Pirko { 974a5facc4cSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 9755c0418edSLeon Romanovsky struct nsim_bus_dev *nsim_bus_dev; 9765c0418edSLeon Romanovsky int ret; 9775c0418edSLeon Romanovsky 9785c0418edSLeon Romanovsky nsim_bus_dev = nsim_dev->nsim_bus_dev; 9795c0418edSLeon Romanovsky mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock); 9805c0418edSLeon Romanovsky nsim_bus_dev->in_reload = false; 9818fb4bc6fSJiri Pirko 982155ddfc5SJiri Pirko if (nsim_dev->fail_reload) { 983155ddfc5SJiri Pirko /* For testing purposes, user set debugfs fail_reload 984155ddfc5SJiri Pirko * value to true. Fail right away. 985155ddfc5SJiri Pirko */ 986155ddfc5SJiri Pirko NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); 9875c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 988155ddfc5SJiri Pirko return -EINVAL; 989155ddfc5SJiri Pirko } 990155ddfc5SJiri Pirko 991ccdf0721SMoshe Shemesh *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 9925c0418edSLeon Romanovsky ret = nsim_dev_reload_create(nsim_dev, extack); 9935c0418edSLeon Romanovsky mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock); 9945c0418edSLeon Romanovsky return ret; 9958fb4bc6fSJiri Pirko } 9968fb4bc6fSJiri Pirko 9978e23cc03SJiri Pirko static int nsim_dev_info_get(struct devlink *devlink, 9988e23cc03SJiri Pirko struct devlink_info_req *req, 9998e23cc03SJiri Pirko struct netlink_ext_ack *extack) 10008e23cc03SJiri Pirko { 10018e23cc03SJiri Pirko return devlink_info_driver_name_put(req, DRV_NAME); 10028e23cc03SJiri Pirko } 10038e23cc03SJiri Pirko 1004fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000 1005fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 1006fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 1007fa4dfc4aSJiri Pirko 1008bc75c054SJacob Keller static int nsim_dev_flash_update(struct devlink *devlink, 1009bc75c054SJacob Keller struct devlink_flash_update_params *params, 1010fa4dfc4aSJiri Pirko struct netlink_ext_ack *extack) 1011fa4dfc4aSJiri Pirko { 1012fa4dfc4aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 1013fa4dfc4aSJiri Pirko int i; 1014fa4dfc4aSJiri Pirko 1015cbb58368SJacob Keller if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0) 1016cbb58368SJacob Keller return -EOPNOTSUPP; 1017cbb58368SJacob Keller 1018fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1019fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, 1020fa4dfc4aSJiri Pirko "Preparing to flash", 1021bc75c054SJacob Keller params->component, 0, 0); 1022fa4dfc4aSJiri Pirko } 1023fa4dfc4aSJiri Pirko 1024fa4dfc4aSJiri Pirko for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 1025fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) 1026fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1027bc75c054SJacob Keller params->component, 1028fa4dfc4aSJiri Pirko i * NSIM_DEV_FLASH_CHUNK_SIZE, 1029fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1030fa4dfc4aSJiri Pirko msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 1031fa4dfc4aSJiri Pirko } 1032fa4dfc4aSJiri Pirko 1033fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 1034fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 1035bc75c054SJacob Keller params->component, 1036fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE, 1037fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 1038b311b001SShannon Nelson devlink_flash_update_timeout_notify(devlink, "Flash select", 1039bc75c054SJacob Keller params->component, 81); 1040fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing done", 1041bc75c054SJacob Keller params->component, 0, 0); 1042fa4dfc4aSJiri Pirko } 1043fa4dfc4aSJiri Pirko 1044fa4dfc4aSJiri Pirko return 0; 1045fa4dfc4aSJiri Pirko } 1046fa4dfc4aSJiri Pirko 1047da58f90fSIdo Schimmel static struct nsim_trap_item * 1048da58f90fSIdo Schimmel nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id) 1049da58f90fSIdo Schimmel { 1050da58f90fSIdo Schimmel struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data; 1051da58f90fSIdo Schimmel int i; 1052da58f90fSIdo Schimmel 1053da58f90fSIdo Schimmel for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) { 1054da58f90fSIdo Schimmel if (nsim_traps_arr[i].id == trap_id) 1055da58f90fSIdo Schimmel return &nsim_trap_data->trap_items_arr[i]; 1056da58f90fSIdo Schimmel } 1057da58f90fSIdo Schimmel 1058da58f90fSIdo Schimmel return NULL; 1059da58f90fSIdo Schimmel } 1060da58f90fSIdo Schimmel 1061da58f90fSIdo Schimmel static int nsim_dev_devlink_trap_init(struct devlink *devlink, 1062da58f90fSIdo Schimmel const struct devlink_trap *trap, 1063da58f90fSIdo Schimmel void *trap_ctx) 1064da58f90fSIdo Schimmel { 1065da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1066da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1067da58f90fSIdo Schimmel 1068da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1069da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1070da58f90fSIdo Schimmel return -ENOENT; 1071da58f90fSIdo Schimmel 1072da58f90fSIdo Schimmel nsim_trap_item->trap_ctx = trap_ctx; 1073da58f90fSIdo Schimmel nsim_trap_item->action = trap->init_action; 1074da58f90fSIdo Schimmel 1075da58f90fSIdo Schimmel return 0; 1076da58f90fSIdo Schimmel } 1077da58f90fSIdo Schimmel 1078da58f90fSIdo Schimmel static int 1079da58f90fSIdo Schimmel nsim_dev_devlink_trap_action_set(struct devlink *devlink, 1080da58f90fSIdo Schimmel const struct devlink_trap *trap, 1081c88e11e0SIdo Schimmel enum devlink_trap_action action, 1082c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 1083da58f90fSIdo Schimmel { 1084da58f90fSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1085da58f90fSIdo Schimmel struct nsim_trap_item *nsim_trap_item; 1086da58f90fSIdo Schimmel 1087da58f90fSIdo Schimmel nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id); 1088da58f90fSIdo Schimmel if (WARN_ON(!nsim_trap_item)) 1089da58f90fSIdo Schimmel return -ENOENT; 1090da58f90fSIdo Schimmel 1091da58f90fSIdo Schimmel spin_lock(&nsim_dev->trap_data->trap_lock); 1092da58f90fSIdo Schimmel nsim_trap_item->action = action; 1093da58f90fSIdo Schimmel spin_unlock(&nsim_dev->trap_data->trap_lock); 1094da58f90fSIdo Schimmel 1095da58f90fSIdo Schimmel return 0; 1096da58f90fSIdo Schimmel } 1097da58f90fSIdo Schimmel 1098ad188458SIdo Schimmel static int 10990dc8249aSIdo Schimmel nsim_dev_devlink_trap_group_set(struct devlink *devlink, 11000dc8249aSIdo Schimmel const struct devlink_trap_group *group, 1101c88e11e0SIdo Schimmel const struct devlink_trap_policer *policer, 1102c88e11e0SIdo Schimmel struct netlink_ext_ack *extack) 11030dc8249aSIdo Schimmel { 11040dc8249aSIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 11050dc8249aSIdo Schimmel 11060dc8249aSIdo Schimmel if (nsim_dev->fail_trap_group_set) 11070dc8249aSIdo Schimmel return -EINVAL; 11080dc8249aSIdo Schimmel 11090dc8249aSIdo Schimmel return 0; 11100dc8249aSIdo Schimmel } 11110dc8249aSIdo Schimmel 11120dc8249aSIdo Schimmel static int 1113ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_set(struct devlink *devlink, 1114ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1115ad188458SIdo Schimmel u64 rate, u64 burst, 1116ad188458SIdo Schimmel struct netlink_ext_ack *extack) 1117ad188458SIdo Schimmel { 1118ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1119ad188458SIdo Schimmel 1120ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_set) { 1121ad188458SIdo Schimmel NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes"); 1122ad188458SIdo Schimmel return -EINVAL; 1123ad188458SIdo Schimmel } 1124ad188458SIdo Schimmel 1125ad188458SIdo Schimmel return 0; 1126ad188458SIdo Schimmel } 1127ad188458SIdo Schimmel 1128ad188458SIdo Schimmel static int 1129ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink, 1130ad188458SIdo Schimmel const struct devlink_trap_policer *policer, 1131ad188458SIdo Schimmel u64 *p_drops) 1132ad188458SIdo Schimmel { 1133ad188458SIdo Schimmel struct nsim_dev *nsim_dev = devlink_priv(devlink); 1134ad188458SIdo Schimmel u64 *cnt; 1135ad188458SIdo Schimmel 1136ad188458SIdo Schimmel if (nsim_dev->fail_trap_policer_counter_get) 1137ad188458SIdo Schimmel return -EINVAL; 1138ad188458SIdo Schimmel 1139ad188458SIdo Schimmel cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1]; 1140be43224fSIdo Schimmel *p_drops = (*cnt)++; 1141ad188458SIdo Schimmel 1142ad188458SIdo Schimmel return 0; 1143ad188458SIdo Schimmel } 1144ad188458SIdo Schimmel 1145605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_MAX 5000 /* Mbps */ 1146605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_UNIT 125000 /* 1 Mbps given in bytes/sec to avoid 1147605c4f8fSDmytro Linkin * u64 overflow during conversion from 1148605c4f8fSDmytro Linkin * bytes to bits. 1149605c4f8fSDmytro Linkin */ 1150605c4f8fSDmytro Linkin 1151605c4f8fSDmytro Linkin static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack) 1152605c4f8fSDmytro Linkin { 1153605c4f8fSDmytro Linkin u64 val; 1154605c4f8fSDmytro Linkin u32 rem; 1155605c4f8fSDmytro Linkin 1156605c4f8fSDmytro Linkin val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem); 1157605c4f8fSDmytro Linkin if (rem) { 1158605c4f8fSDmytro Linkin pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n", 1159605c4f8fSDmytro Linkin name, *rate); 1160605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps."); 1161605c4f8fSDmytro Linkin return -EINVAL; 1162605c4f8fSDmytro Linkin } 1163605c4f8fSDmytro Linkin 1164605c4f8fSDmytro Linkin if (val > NSIM_LINK_SPEED_MAX) { 1165605c4f8fSDmytro Linkin pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n", 1166605c4f8fSDmytro Linkin name, val); 1167605c4f8fSDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps."); 1168605c4f8fSDmytro Linkin return -EINVAL; 1169605c4f8fSDmytro Linkin } 1170605c4f8fSDmytro Linkin *rate = val; 1171605c4f8fSDmytro Linkin return 0; 1172605c4f8fSDmytro Linkin } 1173605c4f8fSDmytro Linkin 1174605c4f8fSDmytro Linkin static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1175605c4f8fSDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1176605c4f8fSDmytro Linkin { 1177605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11785e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1179605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1180605c4f8fSDmytro Linkin int err; 1181605c4f8fSDmytro Linkin 1182605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1183605c4f8fSDmytro Linkin if (err) 1184605c4f8fSDmytro Linkin return err; 1185605c4f8fSDmytro Linkin 11865e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].min_tx_rate = tx_share; 1187605c4f8fSDmytro Linkin return 0; 1188605c4f8fSDmytro Linkin } 1189605c4f8fSDmytro Linkin 1190605c4f8fSDmytro Linkin static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1191605c4f8fSDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1192605c4f8fSDmytro Linkin { 1193605c4f8fSDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv; 11945e388f3dSJakub Kicinski struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev; 1195605c4f8fSDmytro Linkin int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index); 1196605c4f8fSDmytro Linkin int err; 1197605c4f8fSDmytro Linkin 1198605c4f8fSDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1199605c4f8fSDmytro Linkin if (err) 1200605c4f8fSDmytro Linkin return err; 1201605c4f8fSDmytro Linkin 12025e388f3dSJakub Kicinski nsim_dev->vfconfigs[vf_id].max_tx_rate = tx_max; 1203605c4f8fSDmytro Linkin return 0; 1204605c4f8fSDmytro Linkin } 1205605c4f8fSDmytro Linkin 1206885226f5SDmytro Linkin struct nsim_rate_node { 1207885226f5SDmytro Linkin struct dentry *ddir; 1208f3d101b4SDmytro Linkin struct dentry *rate_parent; 1209f3d101b4SDmytro Linkin char *parent_name; 1210885226f5SDmytro Linkin u16 tx_share; 1211885226f5SDmytro Linkin u16 tx_max; 1212885226f5SDmytro Linkin }; 1213885226f5SDmytro Linkin 1214885226f5SDmytro Linkin static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv, 1215885226f5SDmytro Linkin u64 tx_share, struct netlink_ext_ack *extack) 1216885226f5SDmytro Linkin { 1217885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1218885226f5SDmytro Linkin int err; 1219885226f5SDmytro Linkin 1220885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack); 1221885226f5SDmytro Linkin if (err) 1222885226f5SDmytro Linkin return err; 1223885226f5SDmytro Linkin 1224885226f5SDmytro Linkin nsim_node->tx_share = tx_share; 1225885226f5SDmytro Linkin return 0; 1226885226f5SDmytro Linkin } 1227885226f5SDmytro Linkin 1228885226f5SDmytro Linkin static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv, 1229885226f5SDmytro Linkin u64 tx_max, struct netlink_ext_ack *extack) 1230885226f5SDmytro Linkin { 1231885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1232885226f5SDmytro Linkin int err; 1233885226f5SDmytro Linkin 1234885226f5SDmytro Linkin err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack); 1235885226f5SDmytro Linkin if (err) 1236885226f5SDmytro Linkin return err; 1237885226f5SDmytro Linkin 1238885226f5SDmytro Linkin nsim_node->tx_max = tx_max; 1239885226f5SDmytro Linkin return 0; 1240885226f5SDmytro Linkin } 1241885226f5SDmytro Linkin 1242885226f5SDmytro Linkin static int nsim_rate_node_new(struct devlink_rate *node, void **priv, 1243885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1244885226f5SDmytro Linkin { 1245885226f5SDmytro Linkin struct nsim_dev *nsim_dev = devlink_priv(node->devlink); 1246885226f5SDmytro Linkin struct nsim_rate_node *nsim_node; 1247885226f5SDmytro Linkin 1248885226f5SDmytro Linkin if (!nsim_esw_mode_is_switchdev(nsim_dev)) { 1249885226f5SDmytro Linkin NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode."); 1250885226f5SDmytro Linkin return -EOPNOTSUPP; 1251885226f5SDmytro Linkin } 1252885226f5SDmytro Linkin 1253885226f5SDmytro Linkin nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL); 1254885226f5SDmytro Linkin if (!nsim_node) 1255885226f5SDmytro Linkin return -ENOMEM; 1256885226f5SDmytro Linkin 1257885226f5SDmytro Linkin nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir); 12584e744cb8SDan Carpenter 1259885226f5SDmytro Linkin debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share); 1260885226f5SDmytro Linkin debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max); 1261f3d101b4SDmytro Linkin nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400, 1262f3d101b4SDmytro Linkin nsim_node->ddir, 1263f3d101b4SDmytro Linkin &nsim_node->parent_name, 1264f3d101b4SDmytro Linkin &nsim_dev_rate_parent_fops); 1265f3d101b4SDmytro Linkin 1266885226f5SDmytro Linkin *priv = nsim_node; 1267885226f5SDmytro Linkin return 0; 1268885226f5SDmytro Linkin } 1269885226f5SDmytro Linkin 1270885226f5SDmytro Linkin static int nsim_rate_node_del(struct devlink_rate *node, void *priv, 1271885226f5SDmytro Linkin struct netlink_ext_ack *extack) 1272885226f5SDmytro Linkin { 1273885226f5SDmytro Linkin struct nsim_rate_node *nsim_node = priv; 1274885226f5SDmytro Linkin 1275f3d101b4SDmytro Linkin debugfs_remove(nsim_node->rate_parent); 1276885226f5SDmytro Linkin debugfs_remove_recursive(nsim_node->ddir); 1277885226f5SDmytro Linkin kfree(nsim_node); 1278885226f5SDmytro Linkin return 0; 1279885226f5SDmytro Linkin } 1280885226f5SDmytro Linkin 1281f3d101b4SDmytro Linkin static int nsim_rate_leaf_parent_set(struct devlink_rate *child, 1282f3d101b4SDmytro Linkin struct devlink_rate *parent, 1283f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1284f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1285f3d101b4SDmytro Linkin { 1286f3d101b4SDmytro Linkin struct nsim_dev_port *nsim_dev_port = priv_child; 1287f3d101b4SDmytro Linkin 1288f3d101b4SDmytro Linkin if (parent) 1289f3d101b4SDmytro Linkin nsim_dev_port->parent_name = parent->name; 1290f3d101b4SDmytro Linkin else 1291f3d101b4SDmytro Linkin nsim_dev_port->parent_name = NULL; 1292f3d101b4SDmytro Linkin return 0; 1293f3d101b4SDmytro Linkin } 1294f3d101b4SDmytro Linkin 1295f3d101b4SDmytro Linkin static int nsim_rate_node_parent_set(struct devlink_rate *child, 1296f3d101b4SDmytro Linkin struct devlink_rate *parent, 1297f3d101b4SDmytro Linkin void *priv_child, void *priv_parent, 1298f3d101b4SDmytro Linkin struct netlink_ext_ack *extack) 1299f3d101b4SDmytro Linkin { 1300f3d101b4SDmytro Linkin struct nsim_rate_node *nsim_node = priv_child; 1301f3d101b4SDmytro Linkin 1302f3d101b4SDmytro Linkin if (parent) 1303f3d101b4SDmytro Linkin nsim_node->parent_name = parent->name; 1304f3d101b4SDmytro Linkin else 1305f3d101b4SDmytro Linkin nsim_node->parent_name = NULL; 1306f3d101b4SDmytro Linkin return 0; 1307f3d101b4SDmytro Linkin } 1308f3d101b4SDmytro Linkin 1309a7b3527aSOleksandr Mazur static int 1310275b51c2SOleksandr Mazur nsim_dev_devlink_trap_drop_counter_get(struct devlink *devlink, 1311a7b3527aSOleksandr Mazur const struct devlink_trap *trap, 1312a7b3527aSOleksandr Mazur u64 *p_drops) 1313a7b3527aSOleksandr Mazur { 1314a7b3527aSOleksandr Mazur struct nsim_dev *nsim_dev = devlink_priv(devlink); 1315a7b3527aSOleksandr Mazur u64 *cnt; 1316a7b3527aSOleksandr Mazur 1317275b51c2SOleksandr Mazur if (nsim_dev->fail_trap_drop_counter_get) 1318a7b3527aSOleksandr Mazur return -EINVAL; 1319a7b3527aSOleksandr Mazur 1320a7b3527aSOleksandr Mazur cnt = &nsim_dev->trap_data->trap_pkt_cnt; 1321a7b3527aSOleksandr Mazur *p_drops = (*cnt)++; 1322a7b3527aSOleksandr Mazur 1323a7b3527aSOleksandr Mazur return 0; 1324a7b3527aSOleksandr Mazur } 1325a7b3527aSOleksandr Mazur 13268fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 1327160dc373SDmytro Linkin .eswitch_mode_set = nsim_devlink_eswitch_mode_set, 1328160dc373SDmytro Linkin .eswitch_mode_get = nsim_devlink_eswitch_mode_get, 1329cbb58368SJacob Keller .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT | 1330cbb58368SJacob Keller DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, 1331ccdf0721SMoshe Shemesh .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), 133297691069SJiri Pirko .reload_down = nsim_dev_reload_down, 133397691069SJiri Pirko .reload_up = nsim_dev_reload_up, 13348e23cc03SJiri Pirko .info_get = nsim_dev_info_get, 1335fa4dfc4aSJiri Pirko .flash_update = nsim_dev_flash_update, 1336da58f90fSIdo Schimmel .trap_init = nsim_dev_devlink_trap_init, 1337da58f90fSIdo Schimmel .trap_action_set = nsim_dev_devlink_trap_action_set, 13380dc8249aSIdo Schimmel .trap_group_set = nsim_dev_devlink_trap_group_set, 1339ad188458SIdo Schimmel .trap_policer_set = nsim_dev_devlink_trap_policer_set, 1340ad188458SIdo Schimmel .trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get, 1341605c4f8fSDmytro Linkin .rate_leaf_tx_share_set = nsim_leaf_tx_share_set, 1342605c4f8fSDmytro Linkin .rate_leaf_tx_max_set = nsim_leaf_tx_max_set, 1343885226f5SDmytro Linkin .rate_node_tx_share_set = nsim_node_tx_share_set, 1344885226f5SDmytro Linkin .rate_node_tx_max_set = nsim_node_tx_max_set, 1345885226f5SDmytro Linkin .rate_node_new = nsim_rate_node_new, 1346885226f5SDmytro Linkin .rate_node_del = nsim_rate_node_del, 1347f3d101b4SDmytro Linkin .rate_leaf_parent_set = nsim_rate_leaf_parent_set, 1348f3d101b4SDmytro Linkin .rate_node_parent_set = nsim_rate_node_parent_set, 1349275b51c2SOleksandr Mazur .trap_drop_counter_get = nsim_dev_devlink_trap_drop_counter_get, 13508fb4bc6fSJiri Pirko }; 13518fb4bc6fSJiri Pirko 1352150e8f8aSJiri Pirko #define NSIM_DEV_MAX_MACS_DEFAULT 32 1353150e8f8aSJiri Pirko #define NSIM_DEV_TEST1_DEFAULT true 1354150e8f8aSJiri Pirko 1355814b9ce6SDmytro Linkin static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1356794b2c05SJiri Pirko unsigned int port_index) 13578320d145SJiri Pirko { 135871ad8d55SDanielle Ratson struct devlink_port_attrs attrs = {}; 13598320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port; 13608320d145SJiri Pirko struct devlink_port *devlink_port; 13618320d145SJiri Pirko int err; 13628320d145SJiri Pirko 13635e388f3dSJakub Kicinski if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_dev_get_vfs(nsim_dev)) 136492ba1f29SDmytro Linkin return -EINVAL; 136592ba1f29SDmytro Linkin 13668320d145SJiri Pirko nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); 13678320d145SJiri Pirko if (!nsim_dev_port) 13688320d145SJiri Pirko return -ENOMEM; 1369814b9ce6SDmytro Linkin nsim_dev_port->port_index = nsim_dev_port_index(type, port_index); 1370814b9ce6SDmytro Linkin nsim_dev_port->port_type = type; 13718320d145SJiri Pirko 13728320d145SJiri Pirko devlink_port = &nsim_dev_port->devlink_port; 137392ba1f29SDmytro Linkin if (nsim_dev_port_is_pf(nsim_dev_port)) { 137471ad8d55SDanielle Ratson attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 137571ad8d55SDanielle Ratson attrs.phys.port_number = port_index + 1; 137692ba1f29SDmytro Linkin } else { 137792ba1f29SDmytro Linkin attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; 137892ba1f29SDmytro Linkin attrs.pci_vf.pf = 0; 137992ba1f29SDmytro Linkin attrs.pci_vf.vf = port_index; 138092ba1f29SDmytro Linkin } 138171ad8d55SDanielle Ratson memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 138271ad8d55SDanielle Ratson attrs.switch_id.id_len = nsim_dev->switch_id.id_len; 138371ad8d55SDanielle Ratson devlink_port_attrs_set(devlink_port, &attrs); 1384*76eea6c2SJakub Kicinski err = devl_port_register(priv_to_devlink(nsim_dev), devlink_port, 1385814b9ce6SDmytro Linkin nsim_dev_port->port_index); 13868320d145SJiri Pirko if (err) 13878320d145SJiri Pirko goto err_port_free; 13888320d145SJiri Pirko 13898320d145SJiri Pirko err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 13908320d145SJiri Pirko if (err) 13918320d145SJiri Pirko goto err_dl_port_unregister; 13928320d145SJiri Pirko 1393e05b2d14SJiri Pirko nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 1394e05b2d14SJiri Pirko if (IS_ERR(nsim_dev_port->ns)) { 1395e05b2d14SJiri Pirko err = PTR_ERR(nsim_dev_port->ns); 1396e05b2d14SJiri Pirko goto err_port_debugfs_exit; 1397e05b2d14SJiri Pirko } 1398e05b2d14SJiri Pirko 1399885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) { 1400*76eea6c2SJakub Kicinski err = devl_rate_leaf_create(&nsim_dev_port->devlink_port, 1401885dfe12SDmytro Linkin nsim_dev_port); 1402885dfe12SDmytro Linkin if (err) 1403885dfe12SDmytro Linkin goto err_nsim_destroy; 1404885dfe12SDmytro Linkin } 1405885dfe12SDmytro Linkin 1406e05b2d14SJiri Pirko devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); 14078320d145SJiri Pirko list_add(&nsim_dev_port->list, &nsim_dev->port_list); 14088320d145SJiri Pirko 14098320d145SJiri Pirko return 0; 14108320d145SJiri Pirko 1411885dfe12SDmytro Linkin err_nsim_destroy: 1412885dfe12SDmytro Linkin nsim_destroy(nsim_dev_port->ns); 1413e05b2d14SJiri Pirko err_port_debugfs_exit: 1414e05b2d14SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 14158320d145SJiri Pirko err_dl_port_unregister: 1416*76eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14178320d145SJiri Pirko err_port_free: 14188320d145SJiri Pirko kfree(nsim_dev_port); 14198320d145SJiri Pirko return err; 14208320d145SJiri Pirko } 14218320d145SJiri Pirko 1422794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 14238320d145SJiri Pirko { 14248320d145SJiri Pirko struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 14258320d145SJiri Pirko 14268320d145SJiri Pirko list_del(&nsim_dev_port->list); 1427885dfe12SDmytro Linkin if (nsim_dev_port_is_vf(nsim_dev_port)) 1428*76eea6c2SJakub Kicinski devl_rate_leaf_destroy(&nsim_dev_port->devlink_port); 1429e05b2d14SJiri Pirko devlink_port_type_clear(devlink_port); 1430e05b2d14SJiri Pirko nsim_destroy(nsim_dev_port->ns); 14318320d145SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 1432*76eea6c2SJakub Kicinski devl_port_unregister(devlink_port); 14338320d145SJiri Pirko kfree(nsim_dev_port); 14348320d145SJiri Pirko } 14358320d145SJiri Pirko 14368320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 14378320d145SJiri Pirko { 14388320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port, *tmp; 14398320d145SJiri Pirko 1440*76eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 14418320d145SJiri Pirko list_for_each_entry_safe(nsim_dev_port, tmp, 14428320d145SJiri Pirko &nsim_dev->port_list, list) 1443794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 1444*76eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 14458320d145SJiri Pirko } 14468320d145SJiri Pirko 14477f36a77aSJiri Pirko static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, 14487f36a77aSJiri Pirko unsigned int port_count) 14498320d145SJiri Pirko { 14507f36a77aSJiri Pirko int i, err; 14518320d145SJiri Pirko 14527f36a77aSJiri Pirko for (i = 0; i < port_count; i++) { 1453*76eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1454814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i); 1455*76eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 14568320d145SJiri Pirko if (err) 14578320d145SJiri Pirko goto err_port_del_all; 14588320d145SJiri Pirko } 14598320d145SJiri Pirko return 0; 14608320d145SJiri Pirko 14618320d145SJiri Pirko err_port_del_all: 14628320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 14638320d145SJiri Pirko return err; 14648320d145SJiri Pirko } 14658320d145SJiri Pirko 146675ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, 146775ba029fSJiri Pirko struct netlink_ext_ack *extack) 146875ba029fSJiri Pirko { 146975ba029fSJiri Pirko struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; 147075ba029fSJiri Pirko struct devlink *devlink; 147175ba029fSJiri Pirko int err; 147275ba029fSJiri Pirko 147375ba029fSJiri Pirko devlink = priv_to_devlink(nsim_dev); 147475ba029fSJiri Pirko nsim_dev = devlink_priv(devlink); 147575ba029fSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 147675ba029fSJiri Pirko nsim_dev->fw_update_status = true; 1477cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 147875ba029fSJiri Pirko 147975ba029fSJiri Pirko nsim_devlink_param_load_driverinit_values(devlink); 148075ba029fSJiri Pirko 148175ba029fSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 148275ba029fSJiri Pirko if (err) 1483f57ab5b7SIdo Schimmel return err; 148475ba029fSJiri Pirko 148575ba029fSJiri Pirko err = nsim_dev_traps_init(devlink); 148675ba029fSJiri Pirko if (err) 148775ba029fSJiri Pirko goto err_dummy_region_exit; 148875ba029fSJiri Pirko 1489f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, extack); 1490f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1491f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1492f57ab5b7SIdo Schimmel goto err_traps_exit; 1493f57ab5b7SIdo Schimmel } 1494f57ab5b7SIdo Schimmel 149582c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 149675ba029fSJiri Pirko if (err) 1497f57ab5b7SIdo Schimmel goto err_fib_destroy; 149875ba029fSJiri Pirko 1499a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 150082c93a87SJiri Pirko if (err) 150182c93a87SJiri Pirko goto err_health_exit; 150282c93a87SJiri Pirko 15031a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1504a8700c3dSIdo Schimmel if (err) 1505a8700c3dSIdo Schimmel goto err_psample_exit; 1506a8700c3dSIdo Schimmel 15071a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 15081a6d7ae7SPetr Machata if (err) 15091a6d7ae7SPetr Machata goto err_hwstats_exit; 15101a6d7ae7SPetr Machata 15118526ad96STaehee Yoo nsim_dev->take_snapshot = debugfs_create_file("take_snapshot", 15128526ad96STaehee Yoo 0200, 15138526ad96STaehee Yoo nsim_dev->ddir, 15148526ad96STaehee Yoo nsim_dev, 15158526ad96STaehee Yoo &nsim_dev_take_snapshot_fops); 151675ba029fSJiri Pirko return 0; 151775ba029fSJiri Pirko 15181a6d7ae7SPetr Machata err_hwstats_exit: 15191a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1520a8700c3dSIdo Schimmel err_psample_exit: 1521a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 152282c93a87SJiri Pirko err_health_exit: 152382c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1524f57ab5b7SIdo Schimmel err_fib_destroy: 1525f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 152675ba029fSJiri Pirko err_traps_exit: 152775ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 152875ba029fSJiri Pirko err_dummy_region_exit: 152975ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 153075ba029fSJiri Pirko return err; 153175ba029fSJiri Pirko } 153275ba029fSJiri Pirko 1533a66f64b8SJakub Kicinski int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) 15347f36a77aSJiri Pirko { 15357f36a77aSJiri Pirko struct nsim_dev *nsim_dev; 15367f36a77aSJiri Pirko struct devlink *devlink; 15377f36a77aSJiri Pirko int err; 15387f36a77aSJiri Pirko 153926713455SLeon Romanovsky devlink = devlink_alloc_ns(&nsim_dev_devlink_ops, sizeof(*nsim_dev), 1540919d13a7SLeon Romanovsky nsim_bus_dev->initial_net, &nsim_bus_dev->dev); 15417f36a77aSJiri Pirko if (!devlink) 1542bfcccfe7SJakub Kicinski return -ENOMEM; 15437f36a77aSJiri Pirko nsim_dev = devlink_priv(devlink); 15447f36a77aSJiri Pirko nsim_dev->nsim_bus_dev = nsim_bus_dev; 15457f36a77aSJiri Pirko nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 15467f36a77aSJiri Pirko get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 15477f36a77aSJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 15485e388f3dSJakub Kicinski mutex_init(&nsim_dev->vfs_lock); 15497f36a77aSJiri Pirko nsim_dev->fw_update_status = true; 1550cbb58368SJacob Keller nsim_dev->fw_update_overwrite_mask = 0; 15517f36a77aSJiri Pirko nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; 15527f36a77aSJiri Pirko nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; 1553d3cbb907SJiri Pirko spin_lock_init(&nsim_dev->fa_cookie_lock); 15547f36a77aSJiri Pirko 1555bfcccfe7SJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 1556bfcccfe7SJakub Kicinski 15575e388f3dSJakub Kicinski nsim_dev->vfconfigs = kcalloc(nsim_bus_dev->max_vfs, 15585e388f3dSJakub Kicinski sizeof(struct nsim_vf_config), 15595e388f3dSJakub Kicinski GFP_KERNEL | __GFP_NOWARN); 15605e388f3dSJakub Kicinski if (!nsim_dev->vfconfigs) { 15615e388f3dSJakub Kicinski err = -ENOMEM; 15625e388f3dSJakub Kicinski goto err_devlink_free; 15635e388f3dSJakub Kicinski } 15645e388f3dSJakub Kicinski 15657f36a77aSJiri Pirko err = nsim_dev_resources_register(devlink); 15667f36a77aSJiri Pirko if (err) 15675e388f3dSJakub Kicinski goto err_vfc_free; 15687f36a77aSJiri Pirko 15697f36a77aSJiri Pirko err = devlink_params_register(devlink, nsim_devlink_params, 15707f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 15717f36a77aSJiri Pirko if (err) 15727f36a77aSJiri Pirko goto err_dl_unregister; 15737f36a77aSJiri Pirko nsim_devlink_set_params_init_values(nsim_dev, devlink); 15747f36a77aSJiri Pirko 15757f36a77aSJiri Pirko err = nsim_dev_dummy_region_init(nsim_dev, devlink); 15767f36a77aSJiri Pirko if (err) 15777f36a77aSJiri Pirko goto err_params_unregister; 15787f36a77aSJiri Pirko 15797f36a77aSJiri Pirko err = nsim_dev_traps_init(devlink); 15807f36a77aSJiri Pirko if (err) 15817f36a77aSJiri Pirko goto err_dummy_region_exit; 15827f36a77aSJiri Pirko 15837f36a77aSJiri Pirko err = nsim_dev_debugfs_init(nsim_dev); 15847f36a77aSJiri Pirko if (err) 15857f36a77aSJiri Pirko goto err_traps_exit; 15867f36a77aSJiri Pirko 1587f57ab5b7SIdo Schimmel nsim_dev->fib_data = nsim_fib_create(devlink, NULL); 1588f57ab5b7SIdo Schimmel if (IS_ERR(nsim_dev->fib_data)) { 1589f57ab5b7SIdo Schimmel err = PTR_ERR(nsim_dev->fib_data); 1590f57ab5b7SIdo Schimmel goto err_debugfs_exit; 1591f57ab5b7SIdo Schimmel } 1592f57ab5b7SIdo Schimmel 159382c93a87SJiri Pirko err = nsim_dev_health_init(nsim_dev, devlink); 15947f36a77aSJiri Pirko if (err) 1595f57ab5b7SIdo Schimmel goto err_fib_destroy; 15967f36a77aSJiri Pirko 159782c93a87SJiri Pirko err = nsim_bpf_dev_init(nsim_dev); 159882c93a87SJiri Pirko if (err) 159982c93a87SJiri Pirko goto err_health_exit; 160082c93a87SJiri Pirko 1601a8700c3dSIdo Schimmel err = nsim_dev_psample_init(nsim_dev); 16027f36a77aSJiri Pirko if (err) 16037f36a77aSJiri Pirko goto err_bpf_dev_exit; 16047f36a77aSJiri Pirko 16051a6d7ae7SPetr Machata err = nsim_dev_hwstats_init(nsim_dev); 1606a8700c3dSIdo Schimmel if (err) 1607a8700c3dSIdo Schimmel goto err_psample_exit; 1608a8700c3dSIdo Schimmel 16091a6d7ae7SPetr Machata err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); 16101a6d7ae7SPetr Machata if (err) 16111a6d7ae7SPetr Machata goto err_hwstats_exit; 16121a6d7ae7SPetr Machata 1613160dc373SDmytro Linkin nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY; 1614bd032e35SLeon Romanovsky devlink_set_features(devlink, DEVLINK_F_RELOAD); 161571c1b525SLeon Romanovsky devlink_register(devlink); 1616bfcccfe7SJakub Kicinski return 0; 16177f36a77aSJiri Pirko 16181a6d7ae7SPetr Machata err_hwstats_exit: 16191a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1620a8700c3dSIdo Schimmel err_psample_exit: 1621a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 16227f36a77aSJiri Pirko err_bpf_dev_exit: 16237f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 162482c93a87SJiri Pirko err_health_exit: 162582c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1626f57ab5b7SIdo Schimmel err_fib_destroy: 1627f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 16287f36a77aSJiri Pirko err_debugfs_exit: 16297f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16307f36a77aSJiri Pirko err_traps_exit: 16317f36a77aSJiri Pirko nsim_dev_traps_exit(devlink); 16327f36a77aSJiri Pirko err_dummy_region_exit: 16337f36a77aSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 16347f36a77aSJiri Pirko err_params_unregister: 16357f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16367f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 16377f36a77aSJiri Pirko err_dl_unregister: 16384c897cfcSLeon Romanovsky devlink_resources_unregister(devlink); 16395e388f3dSJakub Kicinski err_vfc_free: 16405e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 16417f36a77aSJiri Pirko err_devlink_free: 16427f36a77aSJiri Pirko devlink_free(devlink); 16435e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 1644bfcccfe7SJakub Kicinski return err; 16457f36a77aSJiri Pirko } 16467f36a77aSJiri Pirko 164775ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) 164875ba029fSJiri Pirko { 164975ba029fSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 165075ba029fSJiri Pirko 165175ba029fSJiri Pirko if (devlink_is_reload_failed(devlink)) 165275ba029fSJiri Pirko return; 16538526ad96STaehee Yoo debugfs_remove(nsim_dev->take_snapshot); 165432ac15d8SDmytro Linkin 16555e388f3dSJakub Kicinski mutex_lock(&nsim_dev->vfs_lock); 16561c401078SJakub Kicinski if (nsim_dev_get_vfs(nsim_dev)) { 16571c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_dev->nsim_bus_dev, 0); 16581c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) 16591c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 16601c401078SJakub Kicinski } 16615e388f3dSJakub Kicinski mutex_unlock(&nsim_dev->vfs_lock); 166232ac15d8SDmytro Linkin 166375ba029fSJiri Pirko nsim_dev_port_del_all(nsim_dev); 16641a6d7ae7SPetr Machata nsim_dev_hwstats_exit(nsim_dev); 1665a8700c3dSIdo Schimmel nsim_dev_psample_exit(nsim_dev); 166682c93a87SJiri Pirko nsim_dev_health_exit(nsim_dev); 1667f57ab5b7SIdo Schimmel nsim_fib_destroy(devlink, nsim_dev->fib_data); 166875ba029fSJiri Pirko nsim_dev_traps_exit(devlink); 166975ba029fSJiri Pirko nsim_dev_dummy_region_exit(nsim_dev); 167075ba029fSJiri Pirko } 167175ba029fSJiri Pirko 1672a66f64b8SJakub Kicinski void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev) 16737f36a77aSJiri Pirko { 1674bfcccfe7SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 16757f36a77aSJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 16767f36a77aSJiri Pirko 167771c1b525SLeon Romanovsky devlink_unregister(devlink); 167875ba029fSJiri Pirko nsim_dev_reload_destroy(nsim_dev); 167975ba029fSJiri Pirko 16807f36a77aSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 16817f36a77aSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 16827f36a77aSJiri Pirko devlink_params_unregister(devlink, nsim_devlink_params, 16837f36a77aSJiri Pirko ARRAY_SIZE(nsim_devlink_params)); 16844c897cfcSLeon Romanovsky devlink_resources_unregister(devlink); 16855e388f3dSJakub Kicinski kfree(nsim_dev->vfconfigs); 16867f36a77aSJiri Pirko devlink_free(devlink); 16875e388f3dSJakub Kicinski dev_set_drvdata(&nsim_bus_dev->dev, NULL); 16887f36a77aSJiri Pirko } 16897f36a77aSJiri Pirko 1690794b2c05SJiri Pirko static struct nsim_dev_port * 1691814b9ce6SDmytro Linkin __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type, 1692814b9ce6SDmytro Linkin unsigned int port_index) 1693794b2c05SJiri Pirko { 1694794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1695794b2c05SJiri Pirko 1696814b9ce6SDmytro Linkin port_index = nsim_dev_port_index(type, port_index); 1697794b2c05SJiri Pirko list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 1698794b2c05SJiri Pirko if (nsim_dev_port->port_index == port_index) 1699794b2c05SJiri Pirko return nsim_dev_port; 1700794b2c05SJiri Pirko return NULL; 1701794b2c05SJiri Pirko } 1702794b2c05SJiri Pirko 1703a66f64b8SJakub Kicinski int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1704794b2c05SJiri Pirko unsigned int port_index) 1705794b2c05SJiri Pirko { 1706794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1707794b2c05SJiri Pirko int err; 1708794b2c05SJiri Pirko 1709*76eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1710814b9ce6SDmytro Linkin if (__nsim_dev_port_lookup(nsim_dev, type, port_index)) 1711794b2c05SJiri Pirko err = -EEXIST; 1712794b2c05SJiri Pirko else 1713814b9ce6SDmytro Linkin err = __nsim_dev_port_add(nsim_dev, type, port_index); 1714*76eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1715794b2c05SJiri Pirko return err; 1716794b2c05SJiri Pirko } 1717794b2c05SJiri Pirko 1718a66f64b8SJakub Kicinski int nsim_drv_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type, 1719794b2c05SJiri Pirko unsigned int port_index) 1720794b2c05SJiri Pirko { 1721794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1722794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 1723794b2c05SJiri Pirko int err = 0; 1724794b2c05SJiri Pirko 1725*76eea6c2SJakub Kicinski devl_lock(priv_to_devlink(nsim_dev)); 1726814b9ce6SDmytro Linkin nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index); 1727794b2c05SJiri Pirko if (!nsim_dev_port) 1728794b2c05SJiri Pirko err = -ENOENT; 1729794b2c05SJiri Pirko else 1730794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 1731*76eea6c2SJakub Kicinski devl_unlock(priv_to_devlink(nsim_dev)); 1732794b2c05SJiri Pirko return err; 1733794b2c05SJiri Pirko } 1734794b2c05SJiri Pirko 17351c401078SJakub Kicinski int nsim_drv_configure_vfs(struct nsim_bus_dev *nsim_bus_dev, 17361c401078SJakub Kicinski unsigned int num_vfs) 17371c401078SJakub Kicinski { 17381c401078SJakub Kicinski struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 1739047304d0SJakub Kicinski int ret = 0; 17401c401078SJakub Kicinski 17411c401078SJakub Kicinski mutex_lock(&nsim_dev->vfs_lock); 1742047304d0SJakub Kicinski if (nsim_bus_dev->num_vfs == num_vfs) 17431c401078SJakub Kicinski goto exit_unlock; 17441c401078SJakub Kicinski if (nsim_bus_dev->num_vfs && num_vfs) { 17451c401078SJakub Kicinski ret = -EBUSY; 17461c401078SJakub Kicinski goto exit_unlock; 17471c401078SJakub Kicinski } 17481c401078SJakub Kicinski if (nsim_bus_dev->max_vfs < num_vfs) { 17491c401078SJakub Kicinski ret = -ENOMEM; 17501c401078SJakub Kicinski goto exit_unlock; 17511c401078SJakub Kicinski } 17521c401078SJakub Kicinski 17531c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, num_vfs); 17541c401078SJakub Kicinski if (nsim_esw_mode_is_switchdev(nsim_dev)) { 17551c401078SJakub Kicinski if (num_vfs) { 17561c401078SJakub Kicinski ret = nsim_esw_switchdev_enable(nsim_dev, NULL); 17571c401078SJakub Kicinski if (ret) { 17581c401078SJakub Kicinski nsim_bus_dev_set_vfs(nsim_bus_dev, 0); 17591c401078SJakub Kicinski goto exit_unlock; 17601c401078SJakub Kicinski } 17611c401078SJakub Kicinski } else { 17621c401078SJakub Kicinski nsim_esw_legacy_enable(nsim_dev, NULL); 17631c401078SJakub Kicinski } 17641c401078SJakub Kicinski } 17651c401078SJakub Kicinski 17661c401078SJakub Kicinski exit_unlock: 17671c401078SJakub Kicinski mutex_unlock(&nsim_dev->vfs_lock); 17681c401078SJakub Kicinski 17691c401078SJakub Kicinski return ret; 17701c401078SJakub Kicinski } 17711c401078SJakub Kicinski 1772d514f41eSJiri Pirko int nsim_dev_init(void) 1773d514f41eSJiri Pirko { 1774ab1d0cc0SJiri Pirko nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 177534611e69Skbuild test robot return PTR_ERR_OR_ZERO(nsim_dev_ddir); 1776d514f41eSJiri Pirko } 1777d514f41eSJiri Pirko 1778d514f41eSJiri Pirko void nsim_dev_exit(void) 1779d514f41eSJiri Pirko { 1780d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev_ddir); 1781d514f41eSJiri Pirko } 1782