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> 208320d145SJiri Pirko #include <linux/list.h> 21794b2c05SJiri Pirko #include <linux/mutex.h> 22514cf64cSJiri Pirko #include <linux/random.h> 238fb4bc6fSJiri Pirko #include <linux/rtnetlink.h> 248fb4bc6fSJiri Pirko #include <net/devlink.h> 258fb4bc6fSJiri Pirko 268fb4bc6fSJiri Pirko #include "netdevsim.h" 278fb4bc6fSJiri Pirko 28d514f41eSJiri Pirko static struct dentry *nsim_dev_ddir; 29d514f41eSJiri Pirko 30d514f41eSJiri Pirko static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev) 31d514f41eSJiri Pirko { 32ab1d0cc0SJiri Pirko char dev_ddir_name[16]; 33d514f41eSJiri Pirko 34ab1d0cc0SJiri Pirko sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id); 35d514f41eSJiri Pirko nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir); 36d514f41eSJiri Pirko if (IS_ERR_OR_NULL(nsim_dev->ddir)) 37d514f41eSJiri Pirko return PTR_ERR_OR_ZERO(nsim_dev->ddir) ?: -EINVAL; 38ab1d0cc0SJiri Pirko nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir); 39ab1d0cc0SJiri Pirko if (IS_ERR_OR_NULL(nsim_dev->ports_ddir)) 40ab1d0cc0SJiri Pirko return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL; 41*fa4dfc4aSJiri Pirko debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir, 42*fa4dfc4aSJiri Pirko &nsim_dev->fw_update_status); 43d514f41eSJiri Pirko return 0; 44d514f41eSJiri Pirko } 45d514f41eSJiri Pirko 46d514f41eSJiri Pirko static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev) 47d514f41eSJiri Pirko { 48ab1d0cc0SJiri Pirko debugfs_remove_recursive(nsim_dev->ports_ddir); 49d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev->ddir); 50d514f41eSJiri Pirko } 51d514f41eSJiri Pirko 528320d145SJiri Pirko static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev, 538320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port) 548320d145SJiri Pirko { 558320d145SJiri Pirko char port_ddir_name[16]; 568320d145SJiri Pirko char dev_link_name[32]; 578320d145SJiri Pirko 588320d145SJiri Pirko sprintf(port_ddir_name, "%u", nsim_dev_port->port_index); 598320d145SJiri Pirko nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name, 608320d145SJiri Pirko nsim_dev->ports_ddir); 618320d145SJiri Pirko if (IS_ERR_OR_NULL(nsim_dev_port->ddir)) 628320d145SJiri Pirko return -ENOMEM; 638320d145SJiri Pirko 648320d145SJiri Pirko sprintf(dev_link_name, "../../../" DRV_NAME "%u", 658320d145SJiri Pirko nsim_dev->nsim_bus_dev->dev.id); 668320d145SJiri Pirko debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name); 678320d145SJiri Pirko 688320d145SJiri Pirko return 0; 698320d145SJiri Pirko } 708320d145SJiri Pirko 718320d145SJiri Pirko static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port) 728320d145SJiri Pirko { 738320d145SJiri Pirko debugfs_remove_recursive(nsim_dev_port->ddir); 748320d145SJiri Pirko } 758320d145SJiri Pirko 768fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv) 778fb4bc6fSJiri Pirko { 788fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 798fb4bc6fSJiri Pirko 808fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 818fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, false); 828fb4bc6fSJiri Pirko } 838fb4bc6fSJiri Pirko 848fb4bc6fSJiri Pirko static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv) 858fb4bc6fSJiri Pirko { 868fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 878fb4bc6fSJiri Pirko 888fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 898fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, false); 908fb4bc6fSJiri Pirko } 918fb4bc6fSJiri Pirko 928fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv) 938fb4bc6fSJiri Pirko { 948fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 958fb4bc6fSJiri Pirko 968fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 978fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, false); 988fb4bc6fSJiri Pirko } 998fb4bc6fSJiri Pirko 1008fb4bc6fSJiri Pirko static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv) 1018fb4bc6fSJiri Pirko { 1028fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = priv; 1038fb4bc6fSJiri Pirko 1048fb4bc6fSJiri Pirko return nsim_fib_get_val(nsim_dev->fib_data, 1058fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, false); 1068fb4bc6fSJiri Pirko } 1078fb4bc6fSJiri Pirko 1088fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink) 1098fb4bc6fSJiri Pirko { 1108fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 1118fb4bc6fSJiri Pirko struct devlink_resource_size_params params = { 1128fb4bc6fSJiri Pirko .size_max = (u64)-1, 1138fb4bc6fSJiri Pirko .size_granularity = 1, 1148fb4bc6fSJiri Pirko .unit = DEVLINK_RESOURCE_UNIT_ENTRY 1158fb4bc6fSJiri Pirko }; 1168fb4bc6fSJiri Pirko int err; 1178fb4bc6fSJiri Pirko u64 n; 1188fb4bc6fSJiri Pirko 1198fb4bc6fSJiri Pirko /* Resources for IPv4 */ 1208fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv4", (u64)-1, 1218fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, 1228fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 1238fb4bc6fSJiri Pirko ¶ms); 1248fb4bc6fSJiri Pirko if (err) { 1258fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 top resource\n"); 1268fb4bc6fSJiri Pirko goto out; 1278fb4bc6fSJiri Pirko } 1288fb4bc6fSJiri Pirko 1298fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 1308fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, true); 1318fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib", n, 1328fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 1338fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 1348fb4bc6fSJiri Pirko if (err) { 1358fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB resource\n"); 1368fb4bc6fSJiri Pirko return err; 1378fb4bc6fSJiri Pirko } 1388fb4bc6fSJiri Pirko 1398fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 1408fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, true); 1418fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", n, 1428fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 1438fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4, ¶ms); 1448fb4bc6fSJiri Pirko if (err) { 1458fb4bc6fSJiri Pirko pr_err("Failed to register IPv4 FIB rules resource\n"); 1468fb4bc6fSJiri Pirko return err; 1478fb4bc6fSJiri Pirko } 1488fb4bc6fSJiri Pirko 1498fb4bc6fSJiri Pirko /* Resources for IPv6 */ 1508fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "IPv6", (u64)-1, 1518fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, 1528fb4bc6fSJiri Pirko DEVLINK_RESOURCE_ID_PARENT_TOP, 1538fb4bc6fSJiri Pirko ¶ms); 1548fb4bc6fSJiri Pirko if (err) { 1558fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 top resource\n"); 1568fb4bc6fSJiri Pirko goto out; 1578fb4bc6fSJiri Pirko } 1588fb4bc6fSJiri Pirko 1598fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 1608fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, true); 1618fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib", n, 1628fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 1638fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 1648fb4bc6fSJiri Pirko if (err) { 1658fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB resource\n"); 1668fb4bc6fSJiri Pirko return err; 1678fb4bc6fSJiri Pirko } 1688fb4bc6fSJiri Pirko 1698fb4bc6fSJiri Pirko n = nsim_fib_get_val(nsim_dev->fib_data, 1708fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, true); 1718fb4bc6fSJiri Pirko err = devlink_resource_register(devlink, "fib-rules", n, 1728fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 1738fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6, ¶ms); 1748fb4bc6fSJiri Pirko if (err) { 1758fb4bc6fSJiri Pirko pr_err("Failed to register IPv6 FIB rules resource\n"); 1768fb4bc6fSJiri Pirko return err; 1778fb4bc6fSJiri Pirko } 1788fb4bc6fSJiri Pirko 1798fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 1808fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, 1818fb4bc6fSJiri Pirko nsim_dev_ipv4_fib_resource_occ_get, 1828fb4bc6fSJiri Pirko nsim_dev); 1838fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 1848fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB_RULES, 1858fb4bc6fSJiri Pirko nsim_dev_ipv4_fib_rules_res_occ_get, 1868fb4bc6fSJiri Pirko nsim_dev); 1878fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 1888fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, 1898fb4bc6fSJiri Pirko nsim_dev_ipv6_fib_resource_occ_get, 1908fb4bc6fSJiri Pirko nsim_dev); 1918fb4bc6fSJiri Pirko devlink_resource_occ_get_register(devlink, 1928fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB_RULES, 1938fb4bc6fSJiri Pirko nsim_dev_ipv6_fib_rules_res_occ_get, 1948fb4bc6fSJiri Pirko nsim_dev); 1958fb4bc6fSJiri Pirko out: 1968fb4bc6fSJiri Pirko return err; 1978fb4bc6fSJiri Pirko } 1988fb4bc6fSJiri Pirko 1998fb4bc6fSJiri Pirko static int nsim_dev_reload(struct devlink *devlink, 2008fb4bc6fSJiri Pirko struct netlink_ext_ack *extack) 2018fb4bc6fSJiri Pirko { 2028fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 2038fb4bc6fSJiri Pirko enum nsim_resource_id res_ids[] = { 2048fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, 2058fb4bc6fSJiri Pirko NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES 2068fb4bc6fSJiri Pirko }; 2078fb4bc6fSJiri Pirko int i; 2088fb4bc6fSJiri Pirko 2098fb4bc6fSJiri Pirko for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { 2108fb4bc6fSJiri Pirko int err; 2118fb4bc6fSJiri Pirko u64 val; 2128fb4bc6fSJiri Pirko 2138fb4bc6fSJiri Pirko err = devlink_resource_size_get(devlink, res_ids[i], &val); 2148fb4bc6fSJiri Pirko if (!err) { 2158fb4bc6fSJiri Pirko err = nsim_fib_set_max(nsim_dev->fib_data, 2168fb4bc6fSJiri Pirko res_ids[i], val, extack); 2178fb4bc6fSJiri Pirko if (err) 2188fb4bc6fSJiri Pirko return err; 2198fb4bc6fSJiri Pirko } 2208fb4bc6fSJiri Pirko } 2218fb4bc6fSJiri Pirko 2228fb4bc6fSJiri Pirko return 0; 2238fb4bc6fSJiri Pirko } 2248fb4bc6fSJiri Pirko 225*fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000 226*fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 227*fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 228*fa4dfc4aSJiri Pirko 229*fa4dfc4aSJiri Pirko static int nsim_dev_flash_update(struct devlink *devlink, const char *file_name, 230*fa4dfc4aSJiri Pirko const char *component, 231*fa4dfc4aSJiri Pirko struct netlink_ext_ack *extack) 232*fa4dfc4aSJiri Pirko { 233*fa4dfc4aSJiri Pirko struct nsim_dev *nsim_dev = devlink_priv(devlink); 234*fa4dfc4aSJiri Pirko int i; 235*fa4dfc4aSJiri Pirko 236*fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 237*fa4dfc4aSJiri Pirko devlink_flash_update_begin_notify(devlink); 238*fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, 239*fa4dfc4aSJiri Pirko "Preparing to flash", 240*fa4dfc4aSJiri Pirko component, 0, 0); 241*fa4dfc4aSJiri Pirko } 242*fa4dfc4aSJiri Pirko 243*fa4dfc4aSJiri Pirko for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { 244*fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) 245*fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 246*fa4dfc4aSJiri Pirko component, 247*fa4dfc4aSJiri Pirko i * NSIM_DEV_FLASH_CHUNK_SIZE, 248*fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 249*fa4dfc4aSJiri Pirko msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); 250*fa4dfc4aSJiri Pirko } 251*fa4dfc4aSJiri Pirko 252*fa4dfc4aSJiri Pirko if (nsim_dev->fw_update_status) { 253*fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing", 254*fa4dfc4aSJiri Pirko component, 255*fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE, 256*fa4dfc4aSJiri Pirko NSIM_DEV_FLASH_SIZE); 257*fa4dfc4aSJiri Pirko devlink_flash_update_status_notify(devlink, "Flashing done", 258*fa4dfc4aSJiri Pirko component, 0, 0); 259*fa4dfc4aSJiri Pirko devlink_flash_update_end_notify(devlink); 260*fa4dfc4aSJiri Pirko } 261*fa4dfc4aSJiri Pirko 262*fa4dfc4aSJiri Pirko return 0; 263*fa4dfc4aSJiri Pirko } 264*fa4dfc4aSJiri Pirko 2658fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = { 2668fb4bc6fSJiri Pirko .reload = nsim_dev_reload, 267*fa4dfc4aSJiri Pirko .flash_update = nsim_dev_flash_update, 2688fb4bc6fSJiri Pirko }; 2698fb4bc6fSJiri Pirko 2708320d145SJiri Pirko static struct nsim_dev * 2718320d145SJiri Pirko nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count) 2728fb4bc6fSJiri Pirko { 2738fb4bc6fSJiri Pirko struct nsim_dev *nsim_dev; 2748fb4bc6fSJiri Pirko struct devlink *devlink; 2758fb4bc6fSJiri Pirko int err; 2768fb4bc6fSJiri Pirko 2778fb4bc6fSJiri Pirko devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev)); 2788fb4bc6fSJiri Pirko if (!devlink) 279a60f9e48SJiri Pirko return ERR_PTR(-ENOMEM); 2808fb4bc6fSJiri Pirko nsim_dev = devlink_priv(devlink); 281d514f41eSJiri Pirko nsim_dev->nsim_bus_dev = nsim_bus_dev; 282514cf64cSJiri Pirko nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); 283514cf64cSJiri Pirko get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); 2848320d145SJiri Pirko INIT_LIST_HEAD(&nsim_dev->port_list); 285794b2c05SJiri Pirko mutex_init(&nsim_dev->port_list_lock); 286*fa4dfc4aSJiri Pirko nsim_dev->fw_update_status = true; 2878fb4bc6fSJiri Pirko 2888fb4bc6fSJiri Pirko nsim_dev->fib_data = nsim_fib_create(); 2898fb4bc6fSJiri Pirko if (IS_ERR(nsim_dev->fib_data)) { 2908fb4bc6fSJiri Pirko err = PTR_ERR(nsim_dev->fib_data); 2918fb4bc6fSJiri Pirko goto err_devlink_free; 2928fb4bc6fSJiri Pirko } 2938fb4bc6fSJiri Pirko 2948fb4bc6fSJiri Pirko err = nsim_dev_resources_register(devlink); 2958fb4bc6fSJiri Pirko if (err) 2968fb4bc6fSJiri Pirko goto err_fib_destroy; 2978fb4bc6fSJiri Pirko 298a60f9e48SJiri Pirko err = devlink_register(devlink, &nsim_bus_dev->dev); 2998fb4bc6fSJiri Pirko if (err) 3008fb4bc6fSJiri Pirko goto err_resources_unregister; 3018fb4bc6fSJiri Pirko 302d514f41eSJiri Pirko err = nsim_dev_debugfs_init(nsim_dev); 303d514f41eSJiri Pirko if (err) 304d514f41eSJiri Pirko goto err_dl_unregister; 305d514f41eSJiri Pirko 306d514f41eSJiri Pirko err = nsim_bpf_dev_init(nsim_dev); 307d514f41eSJiri Pirko if (err) 308d514f41eSJiri Pirko goto err_debugfs_exit; 309d514f41eSJiri Pirko 310a60f9e48SJiri Pirko return nsim_dev; 3118fb4bc6fSJiri Pirko 312d514f41eSJiri Pirko err_debugfs_exit: 313d514f41eSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 314d514f41eSJiri Pirko err_dl_unregister: 315d514f41eSJiri Pirko devlink_unregister(devlink); 3168fb4bc6fSJiri Pirko err_resources_unregister: 3178fb4bc6fSJiri Pirko devlink_resources_unregister(devlink, NULL); 3188fb4bc6fSJiri Pirko err_fib_destroy: 3198fb4bc6fSJiri Pirko nsim_fib_destroy(nsim_dev->fib_data); 3208fb4bc6fSJiri Pirko err_devlink_free: 3218fb4bc6fSJiri Pirko devlink_free(devlink); 322a60f9e48SJiri Pirko return ERR_PTR(err); 3238fb4bc6fSJiri Pirko } 3248fb4bc6fSJiri Pirko 325e05b2d14SJiri Pirko static void nsim_dev_destroy(struct nsim_dev *nsim_dev) 3268fb4bc6fSJiri Pirko { 327a60f9e48SJiri Pirko struct devlink *devlink = priv_to_devlink(nsim_dev); 3288fb4bc6fSJiri Pirko 329d514f41eSJiri Pirko nsim_bpf_dev_exit(nsim_dev); 330d514f41eSJiri Pirko nsim_dev_debugfs_exit(nsim_dev); 3318fb4bc6fSJiri Pirko devlink_unregister(devlink); 3328fb4bc6fSJiri Pirko devlink_resources_unregister(devlink, NULL); 3338fb4bc6fSJiri Pirko nsim_fib_destroy(nsim_dev->fib_data); 334794b2c05SJiri Pirko mutex_destroy(&nsim_dev->port_list_lock); 3358fb4bc6fSJiri Pirko devlink_free(devlink); 3368fb4bc6fSJiri Pirko } 337d514f41eSJiri Pirko 338794b2c05SJiri Pirko static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, 339794b2c05SJiri Pirko unsigned int port_index) 3408320d145SJiri Pirko { 3418320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port; 3428320d145SJiri Pirko struct devlink_port *devlink_port; 3438320d145SJiri Pirko int err; 3448320d145SJiri Pirko 3458320d145SJiri Pirko nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); 3468320d145SJiri Pirko if (!nsim_dev_port) 3478320d145SJiri Pirko return -ENOMEM; 3488320d145SJiri Pirko nsim_dev_port->port_index = port_index; 3498320d145SJiri Pirko 3508320d145SJiri Pirko devlink_port = &nsim_dev_port->devlink_port; 3518320d145SJiri Pirko devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL, 3528320d145SJiri Pirko port_index + 1, 0, 0, 3538320d145SJiri Pirko nsim_dev->switch_id.id, 3548320d145SJiri Pirko nsim_dev->switch_id.id_len); 3558320d145SJiri Pirko err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port, 3568320d145SJiri Pirko port_index); 3578320d145SJiri Pirko if (err) 3588320d145SJiri Pirko goto err_port_free; 3598320d145SJiri Pirko 3608320d145SJiri Pirko err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); 3618320d145SJiri Pirko if (err) 3628320d145SJiri Pirko goto err_dl_port_unregister; 3638320d145SJiri Pirko 364e05b2d14SJiri Pirko nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); 365e05b2d14SJiri Pirko if (IS_ERR(nsim_dev_port->ns)) { 366e05b2d14SJiri Pirko err = PTR_ERR(nsim_dev_port->ns); 367e05b2d14SJiri Pirko goto err_port_debugfs_exit; 368e05b2d14SJiri Pirko } 369e05b2d14SJiri Pirko 370e05b2d14SJiri Pirko devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); 3718320d145SJiri Pirko list_add(&nsim_dev_port->list, &nsim_dev->port_list); 3728320d145SJiri Pirko 3738320d145SJiri Pirko return 0; 3748320d145SJiri Pirko 375e05b2d14SJiri Pirko err_port_debugfs_exit: 376e05b2d14SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 3778320d145SJiri Pirko err_dl_port_unregister: 3788320d145SJiri Pirko devlink_port_unregister(devlink_port); 3798320d145SJiri Pirko err_port_free: 3808320d145SJiri Pirko kfree(nsim_dev_port); 3818320d145SJiri Pirko return err; 3828320d145SJiri Pirko } 3838320d145SJiri Pirko 384794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) 3858320d145SJiri Pirko { 3868320d145SJiri Pirko struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; 3878320d145SJiri Pirko 3888320d145SJiri Pirko list_del(&nsim_dev_port->list); 389e05b2d14SJiri Pirko devlink_port_type_clear(devlink_port); 390e05b2d14SJiri Pirko nsim_destroy(nsim_dev_port->ns); 3918320d145SJiri Pirko nsim_dev_port_debugfs_exit(nsim_dev_port); 3928320d145SJiri Pirko devlink_port_unregister(devlink_port); 3938320d145SJiri Pirko kfree(nsim_dev_port); 3948320d145SJiri Pirko } 3958320d145SJiri Pirko 3968320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) 3978320d145SJiri Pirko { 3988320d145SJiri Pirko struct nsim_dev_port *nsim_dev_port, *tmp; 3998320d145SJiri Pirko 4008320d145SJiri Pirko list_for_each_entry_safe(nsim_dev_port, tmp, 4018320d145SJiri Pirko &nsim_dev->port_list, list) 402794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 4038320d145SJiri Pirko } 4048320d145SJiri Pirko 4058320d145SJiri Pirko int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) 4068320d145SJiri Pirko { 4078320d145SJiri Pirko struct nsim_dev *nsim_dev; 4088320d145SJiri Pirko int i; 4098320d145SJiri Pirko int err; 4108320d145SJiri Pirko 4118320d145SJiri Pirko nsim_dev = nsim_dev_create(nsim_bus_dev, nsim_bus_dev->port_count); 4128320d145SJiri Pirko if (IS_ERR(nsim_dev)) 4138320d145SJiri Pirko return PTR_ERR(nsim_dev); 4148320d145SJiri Pirko dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); 4158320d145SJiri Pirko 4168320d145SJiri Pirko for (i = 0; i < nsim_bus_dev->port_count; i++) { 417794b2c05SJiri Pirko err = __nsim_dev_port_add(nsim_dev, i); 4188320d145SJiri Pirko if (err) 4198320d145SJiri Pirko goto err_port_del_all; 4208320d145SJiri Pirko } 4218320d145SJiri Pirko return 0; 4228320d145SJiri Pirko 4238320d145SJiri Pirko err_port_del_all: 4248320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 4258320d145SJiri Pirko nsim_dev_destroy(nsim_dev); 4268320d145SJiri Pirko return err; 4278320d145SJiri Pirko } 4288320d145SJiri Pirko 4298320d145SJiri Pirko void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) 4308320d145SJiri Pirko { 4318320d145SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 4328320d145SJiri Pirko 4338320d145SJiri Pirko nsim_dev_port_del_all(nsim_dev); 4348320d145SJiri Pirko nsim_dev_destroy(nsim_dev); 4358320d145SJiri Pirko } 4368320d145SJiri Pirko 437794b2c05SJiri Pirko static struct nsim_dev_port * 438794b2c05SJiri Pirko __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index) 439794b2c05SJiri Pirko { 440794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 441794b2c05SJiri Pirko 442794b2c05SJiri Pirko list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) 443794b2c05SJiri Pirko if (nsim_dev_port->port_index == port_index) 444794b2c05SJiri Pirko return nsim_dev_port; 445794b2c05SJiri Pirko return NULL; 446794b2c05SJiri Pirko } 447794b2c05SJiri Pirko 448794b2c05SJiri Pirko int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, 449794b2c05SJiri Pirko unsigned int port_index) 450794b2c05SJiri Pirko { 451794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 452794b2c05SJiri Pirko int err; 453794b2c05SJiri Pirko 454794b2c05SJiri Pirko mutex_lock(&nsim_dev->port_list_lock); 455794b2c05SJiri Pirko if (__nsim_dev_port_lookup(nsim_dev, port_index)) 456794b2c05SJiri Pirko err = -EEXIST; 457794b2c05SJiri Pirko else 458794b2c05SJiri Pirko err = __nsim_dev_port_add(nsim_dev, port_index); 459794b2c05SJiri Pirko mutex_unlock(&nsim_dev->port_list_lock); 460794b2c05SJiri Pirko return err; 461794b2c05SJiri Pirko } 462794b2c05SJiri Pirko 463794b2c05SJiri Pirko int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, 464794b2c05SJiri Pirko unsigned int port_index) 465794b2c05SJiri Pirko { 466794b2c05SJiri Pirko struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); 467794b2c05SJiri Pirko struct nsim_dev_port *nsim_dev_port; 468794b2c05SJiri Pirko int err = 0; 469794b2c05SJiri Pirko 470794b2c05SJiri Pirko mutex_lock(&nsim_dev->port_list_lock); 471794b2c05SJiri Pirko nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, port_index); 472794b2c05SJiri Pirko if (!nsim_dev_port) 473794b2c05SJiri Pirko err = -ENOENT; 474794b2c05SJiri Pirko else 475794b2c05SJiri Pirko __nsim_dev_port_del(nsim_dev_port); 476794b2c05SJiri Pirko mutex_unlock(&nsim_dev->port_list_lock); 477794b2c05SJiri Pirko return err; 478794b2c05SJiri Pirko } 479794b2c05SJiri Pirko 480d514f41eSJiri Pirko int nsim_dev_init(void) 481d514f41eSJiri Pirko { 482ab1d0cc0SJiri Pirko nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); 483d514f41eSJiri Pirko if (IS_ERR_OR_NULL(nsim_dev_ddir)) 484d514f41eSJiri Pirko return -ENOMEM; 485d514f41eSJiri Pirko return 0; 486d514f41eSJiri Pirko } 487d514f41eSJiri Pirko 488d514f41eSJiri Pirko void nsim_dev_exit(void) 489d514f41eSJiri Pirko { 490d514f41eSJiri Pirko debugfs_remove_recursive(nsim_dev_ddir); 491d514f41eSJiri Pirko } 492