xref: /linux-6.15/drivers/net/netdevsim/dev.c (revision 4e744cb8)
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 
594418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SIZE (1024 * 32)
604418f862SJiri Pirko 
613fe0fd53SJacob Keller static int
62d4602a9fSAndrew Lunn nsim_dev_take_snapshot(struct devlink *devlink,
63d4602a9fSAndrew Lunn 		       const struct devlink_region_ops *ops,
64d4602a9fSAndrew Lunn 		       struct netlink_ext_ack *extack,
653fe0fd53SJacob Keller 		       u8 **data)
664418f862SJiri Pirko {
674418f862SJiri Pirko 	void *dummy_data;
6812102436SJacob Keller 
694418f862SJiri Pirko 	dummy_data = kmalloc(NSIM_DEV_DUMMY_REGION_SIZE, GFP_KERNEL);
704418f862SJiri Pirko 	if (!dummy_data)
714418f862SJiri Pirko 		return -ENOMEM;
724418f862SJiri Pirko 
734418f862SJiri Pirko 	get_random_bytes(dummy_data, NSIM_DEV_DUMMY_REGION_SIZE);
744418f862SJiri Pirko 
753fe0fd53SJacob Keller 	*data = dummy_data;
763fe0fd53SJacob Keller 
773fe0fd53SJacob Keller 	return 0;
783fe0fd53SJacob Keller }
793fe0fd53SJacob Keller 
803fe0fd53SJacob Keller static ssize_t nsim_dev_take_snapshot_write(struct file *file,
813fe0fd53SJacob Keller 					    const char __user *data,
823fe0fd53SJacob Keller 					    size_t count, loff_t *ppos)
833fe0fd53SJacob Keller {
843fe0fd53SJacob Keller 	struct nsim_dev *nsim_dev = file->private_data;
853fe0fd53SJacob Keller 	struct devlink *devlink;
863fe0fd53SJacob Keller 	u8 *dummy_data;
873fe0fd53SJacob Keller 	int err;
883fe0fd53SJacob Keller 	u32 id;
893fe0fd53SJacob Keller 
903fe0fd53SJacob Keller 	devlink = priv_to_devlink(nsim_dev);
913fe0fd53SJacob Keller 
92d4602a9fSAndrew Lunn 	err = nsim_dev_take_snapshot(devlink, NULL, NULL, &dummy_data);
933fe0fd53SJacob Keller 	if (err)
943fe0fd53SJacob Keller 		return err;
953fe0fd53SJacob Keller 
9612102436SJacob Keller 	err = devlink_region_snapshot_id_get(devlink, &id);
977ef19d3bSJacob Keller 	if (err) {
987ef19d3bSJacob Keller 		pr_err("Failed to get snapshot id\n");
993902baf9SGustavo A. R. Silva 		kfree(dummy_data);
1007ef19d3bSJacob Keller 		return err;
1017ef19d3bSJacob Keller 	}
1024418f862SJiri Pirko 	err = devlink_region_snapshot_create(nsim_dev->dummy_region,
103a0a09f6bSJacob Keller 					     dummy_data, id);
10412102436SJacob Keller 	devlink_region_snapshot_id_put(devlink, id);
1054418f862SJiri Pirko 	if (err) {
1064418f862SJiri Pirko 		pr_err("Failed to create region snapshot\n");
1074418f862SJiri Pirko 		kfree(dummy_data);
1084418f862SJiri Pirko 		return err;
1094418f862SJiri Pirko 	}
1104418f862SJiri Pirko 
1114418f862SJiri Pirko 	return count;
1124418f862SJiri Pirko }
1134418f862SJiri Pirko 
1144418f862SJiri Pirko static const struct file_operations nsim_dev_take_snapshot_fops = {
1154418f862SJiri Pirko 	.open = simple_open,
1164418f862SJiri Pirko 	.write = nsim_dev_take_snapshot_write,
1174418f862SJiri Pirko 	.llseek = generic_file_llseek,
118a5bbcbf2STaehee Yoo 	.owner = THIS_MODULE,
1194418f862SJiri Pirko };
1204418f862SJiri Pirko 
121d3cbb907SJiri Pirko static ssize_t nsim_dev_trap_fa_cookie_read(struct file *file,
122d3cbb907SJiri Pirko 					    char __user *data,
123d3cbb907SJiri Pirko 					    size_t count, loff_t *ppos)
124d3cbb907SJiri Pirko {
125d3cbb907SJiri Pirko 	struct nsim_dev *nsim_dev = file->private_data;
126d3cbb907SJiri Pirko 	struct flow_action_cookie *fa_cookie;
127d3cbb907SJiri Pirko 	unsigned int buf_len;
128d3cbb907SJiri Pirko 	ssize_t ret;
129d3cbb907SJiri Pirko 	char *buf;
130d3cbb907SJiri Pirko 
131d3cbb907SJiri Pirko 	spin_lock(&nsim_dev->fa_cookie_lock);
132d3cbb907SJiri Pirko 	fa_cookie = nsim_dev->fa_cookie;
133d3cbb907SJiri Pirko 	if (!fa_cookie) {
134d3cbb907SJiri Pirko 		ret = -EINVAL;
135d3cbb907SJiri Pirko 		goto errout;
136d3cbb907SJiri Pirko 	}
137d3cbb907SJiri Pirko 	buf_len = fa_cookie->cookie_len * 2;
138d3cbb907SJiri Pirko 	buf = kmalloc(buf_len, GFP_ATOMIC);
139d3cbb907SJiri Pirko 	if (!buf) {
140d3cbb907SJiri Pirko 		ret = -ENOMEM;
141d3cbb907SJiri Pirko 		goto errout;
142d3cbb907SJiri Pirko 	}
143d3cbb907SJiri Pirko 	bin2hex(buf, fa_cookie->cookie, fa_cookie->cookie_len);
144d3cbb907SJiri Pirko 	spin_unlock(&nsim_dev->fa_cookie_lock);
145d3cbb907SJiri Pirko 
146d3cbb907SJiri Pirko 	ret = simple_read_from_buffer(data, count, ppos, buf, buf_len);
147d3cbb907SJiri Pirko 
148d3cbb907SJiri Pirko 	kfree(buf);
149d3cbb907SJiri Pirko 	return ret;
150d3cbb907SJiri Pirko 
151d3cbb907SJiri Pirko errout:
152d3cbb907SJiri Pirko 	spin_unlock(&nsim_dev->fa_cookie_lock);
153d3cbb907SJiri Pirko 	return ret;
154d3cbb907SJiri Pirko }
155d3cbb907SJiri Pirko 
156d3cbb907SJiri Pirko static ssize_t nsim_dev_trap_fa_cookie_write(struct file *file,
157d3cbb907SJiri Pirko 					     const char __user *data,
158d3cbb907SJiri Pirko 					     size_t count, loff_t *ppos)
159d3cbb907SJiri Pirko {
160d3cbb907SJiri Pirko 	struct nsim_dev *nsim_dev = file->private_data;
161d3cbb907SJiri Pirko 	struct flow_action_cookie *fa_cookie;
162d3cbb907SJiri Pirko 	size_t cookie_len;
163d3cbb907SJiri Pirko 	ssize_t ret;
164d3cbb907SJiri Pirko 	char *buf;
165d3cbb907SJiri Pirko 
166d3cbb907SJiri Pirko 	if (*ppos != 0)
167d3cbb907SJiri Pirko 		return -EINVAL;
168d3cbb907SJiri Pirko 	cookie_len = (count - 1) / 2;
169d3cbb907SJiri Pirko 	if ((count - 1) % 2)
170d3cbb907SJiri Pirko 		return -EINVAL;
171d3cbb907SJiri Pirko 	buf = kmalloc(count, GFP_KERNEL | __GFP_NOWARN);
172d3cbb907SJiri Pirko 	if (!buf)
173d3cbb907SJiri Pirko 		return -ENOMEM;
174d3cbb907SJiri Pirko 
175d3cbb907SJiri Pirko 	ret = simple_write_to_buffer(buf, count, ppos, data, count);
176d3cbb907SJiri Pirko 	if (ret < 0)
177d3cbb907SJiri Pirko 		goto free_buf;
178d3cbb907SJiri Pirko 
179d3cbb907SJiri Pirko 	fa_cookie = kmalloc(sizeof(*fa_cookie) + cookie_len,
180d3cbb907SJiri Pirko 			    GFP_KERNEL | __GFP_NOWARN);
181d3cbb907SJiri Pirko 	if (!fa_cookie) {
182d3cbb907SJiri Pirko 		ret = -ENOMEM;
183d3cbb907SJiri Pirko 		goto free_buf;
184d3cbb907SJiri Pirko 	}
185d3cbb907SJiri Pirko 
186d3cbb907SJiri Pirko 	fa_cookie->cookie_len = cookie_len;
187d3cbb907SJiri Pirko 	ret = hex2bin(fa_cookie->cookie, buf, cookie_len);
188d3cbb907SJiri Pirko 	if (ret)
189d3cbb907SJiri Pirko 		goto free_fa_cookie;
190d3cbb907SJiri Pirko 	kfree(buf);
191d3cbb907SJiri Pirko 
192d3cbb907SJiri Pirko 	spin_lock(&nsim_dev->fa_cookie_lock);
193d3cbb907SJiri Pirko 	kfree(nsim_dev->fa_cookie);
194d3cbb907SJiri Pirko 	nsim_dev->fa_cookie = fa_cookie;
195d3cbb907SJiri Pirko 	spin_unlock(&nsim_dev->fa_cookie_lock);
196d3cbb907SJiri Pirko 
197d3cbb907SJiri Pirko 	return count;
198d3cbb907SJiri Pirko 
199d3cbb907SJiri Pirko free_fa_cookie:
200d3cbb907SJiri Pirko 	kfree(fa_cookie);
201d3cbb907SJiri Pirko free_buf:
202d3cbb907SJiri Pirko 	kfree(buf);
203d3cbb907SJiri Pirko 	return ret;
204d3cbb907SJiri Pirko }
205d3cbb907SJiri Pirko 
206d3cbb907SJiri Pirko static const struct file_operations nsim_dev_trap_fa_cookie_fops = {
207d3cbb907SJiri Pirko 	.open = simple_open,
208d3cbb907SJiri Pirko 	.read = nsim_dev_trap_fa_cookie_read,
209d3cbb907SJiri Pirko 	.write = nsim_dev_trap_fa_cookie_write,
210d3cbb907SJiri Pirko 	.llseek = generic_file_llseek,
211a5bbcbf2STaehee Yoo 	.owner = THIS_MODULE,
212d3cbb907SJiri Pirko };
213d3cbb907SJiri Pirko 
214d3953819SDmytro Linkin static const struct file_operations nsim_dev_max_vfs_fops = {
215d3953819SDmytro Linkin 	.open = simple_open,
216d3953819SDmytro Linkin 	.read = nsim_bus_dev_max_vfs_read,
217d3953819SDmytro Linkin 	.write = nsim_bus_dev_max_vfs_write,
218d3953819SDmytro Linkin 	.llseek = generic_file_llseek,
219d3953819SDmytro Linkin 	.owner = THIS_MODULE,
220d3953819SDmytro Linkin };
221d3953819SDmytro Linkin 
222d514f41eSJiri Pirko static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
223d514f41eSJiri Pirko {
2246fb8852bSTaehee Yoo 	char dev_ddir_name[sizeof(DRV_NAME) + 10];
225f3d101b4SDmytro Linkin 	int err;
226d514f41eSJiri Pirko 
227ab1d0cc0SJiri Pirko 	sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id);
228d514f41eSJiri Pirko 	nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
2296556ff32STaehee Yoo 	if (IS_ERR(nsim_dev->ddir))
2306556ff32STaehee Yoo 		return PTR_ERR(nsim_dev->ddir);
231ab1d0cc0SJiri Pirko 	nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir);
2326556ff32STaehee Yoo 	if (IS_ERR(nsim_dev->ports_ddir))
2336556ff32STaehee Yoo 		return PTR_ERR(nsim_dev->ports_ddir);
234fa4dfc4aSJiri Pirko 	debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir,
235fa4dfc4aSJiri Pirko 			    &nsim_dev->fw_update_status);
236cbb58368SJacob Keller 	debugfs_create_u32("fw_update_overwrite_mask", 0600, nsim_dev->ddir,
237cbb58368SJacob Keller 			    &nsim_dev->fw_update_overwrite_mask);
238150e8f8aSJiri Pirko 	debugfs_create_u32("max_macs", 0600, nsim_dev->ddir,
239150e8f8aSJiri Pirko 			   &nsim_dev->max_macs);
240150e8f8aSJiri Pirko 	debugfs_create_bool("test1", 0600, nsim_dev->ddir,
241150e8f8aSJiri Pirko 			    &nsim_dev->test1);
2428526ad96STaehee Yoo 	nsim_dev->take_snapshot = debugfs_create_file("take_snapshot",
2438526ad96STaehee Yoo 						      0200,
2448526ad96STaehee Yoo 						      nsim_dev->ddir,
2458526ad96STaehee Yoo 						      nsim_dev,
2464418f862SJiri Pirko 						&nsim_dev_take_snapshot_fops);
247155ddfc5SJiri Pirko 	debugfs_create_bool("dont_allow_reload", 0600, nsim_dev->ddir,
248155ddfc5SJiri Pirko 			    &nsim_dev->dont_allow_reload);
249155ddfc5SJiri Pirko 	debugfs_create_bool("fail_reload", 0600, nsim_dev->ddir,
250155ddfc5SJiri Pirko 			    &nsim_dev->fail_reload);
251d3cbb907SJiri Pirko 	debugfs_create_file("trap_flow_action_cookie", 0600, nsim_dev->ddir,
252d3cbb907SJiri Pirko 			    nsim_dev, &nsim_dev_trap_fa_cookie_fops);
2530dc8249aSIdo Schimmel 	debugfs_create_bool("fail_trap_group_set", 0600,
2540dc8249aSIdo Schimmel 			    nsim_dev->ddir,
2550dc8249aSIdo Schimmel 			    &nsim_dev->fail_trap_group_set);
256ad188458SIdo Schimmel 	debugfs_create_bool("fail_trap_policer_set", 0600,
257ad188458SIdo Schimmel 			    nsim_dev->ddir,
258ad188458SIdo Schimmel 			    &nsim_dev->fail_trap_policer_set);
259ad188458SIdo Schimmel 	debugfs_create_bool("fail_trap_policer_counter_get", 0600,
260ad188458SIdo Schimmel 			    nsim_dev->ddir,
261ad188458SIdo Schimmel 			    &nsim_dev->fail_trap_policer_counter_get);
262d3953819SDmytro Linkin 	nsim_dev->max_vfs = debugfs_create_file("max_vfs",
263d3953819SDmytro Linkin 						0600,
264d3953819SDmytro Linkin 						nsim_dev->ddir,
265d3953819SDmytro Linkin 						nsim_dev->nsim_bus_dev,
266d3953819SDmytro Linkin 						&nsim_dev_max_vfs_fops);
267885226f5SDmytro Linkin 	nsim_dev->nodes_ddir = debugfs_create_dir("rate_nodes", nsim_dev->ddir);
268f3d101b4SDmytro Linkin 	if (IS_ERR(nsim_dev->nodes_ddir)) {
269f3d101b4SDmytro Linkin 		err = PTR_ERR(nsim_dev->nodes_ddir);
270f3d101b4SDmytro Linkin 		goto err_out;
271f3d101b4SDmytro Linkin 	}
272424be63aSJakub Kicinski 	nsim_udp_tunnels_debugfs_create(nsim_dev);
273d514f41eSJiri Pirko 	return 0;
274f3d101b4SDmytro Linkin 
275f3d101b4SDmytro Linkin err_out:
276f3d101b4SDmytro Linkin 	debugfs_remove_recursive(nsim_dev->ports_ddir);
277f3d101b4SDmytro Linkin 	debugfs_remove_recursive(nsim_dev->ddir);
278f3d101b4SDmytro Linkin 	return err;
279d514f41eSJiri Pirko }
280d514f41eSJiri Pirko 
281d514f41eSJiri Pirko static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev)
282d514f41eSJiri Pirko {
283885226f5SDmytro Linkin 	debugfs_remove_recursive(nsim_dev->nodes_ddir);
284ab1d0cc0SJiri Pirko 	debugfs_remove_recursive(nsim_dev->ports_ddir);
285d514f41eSJiri Pirko 	debugfs_remove_recursive(nsim_dev->ddir);
286d514f41eSJiri Pirko }
287d514f41eSJiri Pirko 
288f3d101b4SDmytro Linkin static ssize_t nsim_dev_rate_parent_read(struct file *file,
289f3d101b4SDmytro Linkin 					 char __user *data,
290f3d101b4SDmytro Linkin 					 size_t count, loff_t *ppos)
291f3d101b4SDmytro Linkin {
292f3d101b4SDmytro Linkin 	char **name_ptr = file->private_data;
293f3d101b4SDmytro Linkin 	size_t len;
294f3d101b4SDmytro Linkin 
295f3d101b4SDmytro Linkin 	if (!*name_ptr)
296f3d101b4SDmytro Linkin 		return 0;
297f3d101b4SDmytro Linkin 
298f3d101b4SDmytro Linkin 	len = strlen(*name_ptr);
299f3d101b4SDmytro Linkin 	return simple_read_from_buffer(data, count, ppos, *name_ptr, len);
300f3d101b4SDmytro Linkin }
301f3d101b4SDmytro Linkin 
302f3d101b4SDmytro Linkin static const struct file_operations nsim_dev_rate_parent_fops = {
303f3d101b4SDmytro Linkin 	.open = simple_open,
304f3d101b4SDmytro Linkin 	.read = nsim_dev_rate_parent_read,
305f3d101b4SDmytro Linkin 	.llseek = generic_file_llseek,
306f3d101b4SDmytro Linkin 	.owner = THIS_MODULE,
307f3d101b4SDmytro Linkin };
308f3d101b4SDmytro Linkin 
3098320d145SJiri Pirko static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
3108320d145SJiri Pirko 				      struct nsim_dev_port *nsim_dev_port)
3118320d145SJiri Pirko {
312605c4f8fSDmytro Linkin 	struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev;
313605c4f8fSDmytro Linkin 	unsigned int port_index = nsim_dev_port->port_index;
3148320d145SJiri Pirko 	char port_ddir_name[16];
3158320d145SJiri Pirko 	char dev_link_name[32];
3168320d145SJiri Pirko 
317605c4f8fSDmytro Linkin 	sprintf(port_ddir_name, "%u", port_index);
3188320d145SJiri Pirko 	nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name,
3198320d145SJiri Pirko 						 nsim_dev->ports_ddir);
3206556ff32STaehee Yoo 	if (IS_ERR(nsim_dev_port->ddir))
3216556ff32STaehee Yoo 		return PTR_ERR(nsim_dev_port->ddir);
3228320d145SJiri Pirko 
323605c4f8fSDmytro Linkin 	sprintf(dev_link_name, "../../../" DRV_NAME "%u", nsim_bus_dev->dev.id);
324605c4f8fSDmytro Linkin 	if (nsim_dev_port_is_vf(nsim_dev_port)) {
325605c4f8fSDmytro Linkin 		unsigned int vf_id = nsim_dev_port_index_to_vf_index(port_index);
326605c4f8fSDmytro Linkin 
327605c4f8fSDmytro Linkin 		debugfs_create_u16("tx_share", 0400, nsim_dev_port->ddir,
328605c4f8fSDmytro Linkin 				   &nsim_bus_dev->vfconfigs[vf_id].min_tx_rate);
329605c4f8fSDmytro Linkin 		debugfs_create_u16("tx_max", 0400, nsim_dev_port->ddir,
330605c4f8fSDmytro Linkin 				   &nsim_bus_dev->vfconfigs[vf_id].max_tx_rate);
331f3d101b4SDmytro Linkin 		nsim_dev_port->rate_parent = debugfs_create_file("rate_parent",
332f3d101b4SDmytro Linkin 								 0400,
333f3d101b4SDmytro Linkin 								 nsim_dev_port->ddir,
334f3d101b4SDmytro Linkin 								 &nsim_dev_port->parent_name,
335f3d101b4SDmytro Linkin 								 &nsim_dev_rate_parent_fops);
336605c4f8fSDmytro Linkin 	}
3378320d145SJiri Pirko 	debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name);
3388320d145SJiri Pirko 
3398320d145SJiri Pirko 	return 0;
3408320d145SJiri Pirko }
3418320d145SJiri Pirko 
3428320d145SJiri Pirko static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port)
3438320d145SJiri Pirko {
3448320d145SJiri Pirko 	debugfs_remove_recursive(nsim_dev_port->ddir);
3458320d145SJiri Pirko }
3468320d145SJiri Pirko 
3478fb4bc6fSJiri Pirko static int nsim_dev_resources_register(struct devlink *devlink)
3488fb4bc6fSJiri Pirko {
3498fb4bc6fSJiri Pirko 	struct devlink_resource_size_params params = {
3508fb4bc6fSJiri Pirko 		.size_max = (u64)-1,
3518fb4bc6fSJiri Pirko 		.size_granularity = 1,
3528fb4bc6fSJiri Pirko 		.unit = DEVLINK_RESOURCE_UNIT_ENTRY
3538fb4bc6fSJiri Pirko 	};
3548fb4bc6fSJiri Pirko 	int err;
3558fb4bc6fSJiri Pirko 
3568fb4bc6fSJiri Pirko 	/* Resources for IPv4 */
3578fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "IPv4", (u64)-1,
3588fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4,
3598fb4bc6fSJiri Pirko 					DEVLINK_RESOURCE_ID_PARENT_TOP,
3608fb4bc6fSJiri Pirko 					&params);
3618fb4bc6fSJiri Pirko 	if (err) {
3628fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 top resource\n");
3638fb4bc6fSJiri Pirko 		goto out;
3648fb4bc6fSJiri Pirko 	}
3658fb4bc6fSJiri Pirko 
366a5facc4cSJiri Pirko 	err = devlink_resource_register(devlink, "fib", (u64)-1,
3678fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4_FIB,
3688fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4, &params);
3698fb4bc6fSJiri Pirko 	if (err) {
3708fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 FIB resource\n");
3718fb4bc6fSJiri Pirko 		return err;
3728fb4bc6fSJiri Pirko 	}
3738fb4bc6fSJiri Pirko 
374a5facc4cSJiri Pirko 	err = devlink_resource_register(devlink, "fib-rules", (u64)-1,
3758fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4_FIB_RULES,
3768fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV4, &params);
3778fb4bc6fSJiri Pirko 	if (err) {
3788fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv4 FIB rules resource\n");
3798fb4bc6fSJiri Pirko 		return err;
3808fb4bc6fSJiri Pirko 	}
3818fb4bc6fSJiri Pirko 
3828fb4bc6fSJiri Pirko 	/* Resources for IPv6 */
3838fb4bc6fSJiri Pirko 	err = devlink_resource_register(devlink, "IPv6", (u64)-1,
3848fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6,
3858fb4bc6fSJiri Pirko 					DEVLINK_RESOURCE_ID_PARENT_TOP,
3868fb4bc6fSJiri Pirko 					&params);
3878fb4bc6fSJiri Pirko 	if (err) {
3888fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 top resource\n");
3898fb4bc6fSJiri Pirko 		goto out;
3908fb4bc6fSJiri Pirko 	}
3918fb4bc6fSJiri Pirko 
392a5facc4cSJiri Pirko 	err = devlink_resource_register(devlink, "fib", (u64)-1,
3938fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6_FIB,
3948fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6, &params);
3958fb4bc6fSJiri Pirko 	if (err) {
3968fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 FIB resource\n");
3978fb4bc6fSJiri Pirko 		return err;
3988fb4bc6fSJiri Pirko 	}
3998fb4bc6fSJiri Pirko 
400a5facc4cSJiri Pirko 	err = devlink_resource_register(devlink, "fib-rules", (u64)-1,
4018fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6_FIB_RULES,
4028fb4bc6fSJiri Pirko 					NSIM_RESOURCE_IPV6, &params);
4038fb4bc6fSJiri Pirko 	if (err) {
4048fb4bc6fSJiri Pirko 		pr_err("Failed to register IPv6 FIB rules resource\n");
4058fb4bc6fSJiri Pirko 		return err;
4068fb4bc6fSJiri Pirko 	}
4078fb4bc6fSJiri Pirko 
40835266255SIdo Schimmel 	/* Resources for nexthops */
40935266255SIdo Schimmel 	err = devlink_resource_register(devlink, "nexthops", (u64)-1,
41035266255SIdo Schimmel 					NSIM_RESOURCE_NEXTHOPS,
41135266255SIdo Schimmel 					DEVLINK_RESOURCE_ID_PARENT_TOP,
41235266255SIdo Schimmel 					&params);
41335266255SIdo Schimmel 
4148fb4bc6fSJiri Pirko out:
4158fb4bc6fSJiri Pirko 	return err;
4168fb4bc6fSJiri Pirko }
4178fb4bc6fSJiri Pirko 
418150e8f8aSJiri Pirko enum nsim_devlink_param_id {
419150e8f8aSJiri Pirko 	NSIM_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
420150e8f8aSJiri Pirko 	NSIM_DEVLINK_PARAM_ID_TEST1,
421150e8f8aSJiri Pirko };
422150e8f8aSJiri Pirko 
423150e8f8aSJiri Pirko static const struct devlink_param nsim_devlink_params[] = {
424150e8f8aSJiri Pirko 	DEVLINK_PARAM_GENERIC(MAX_MACS,
425150e8f8aSJiri Pirko 			      BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
426150e8f8aSJiri Pirko 			      NULL, NULL, NULL),
427150e8f8aSJiri Pirko 	DEVLINK_PARAM_DRIVER(NSIM_DEVLINK_PARAM_ID_TEST1,
428150e8f8aSJiri Pirko 			     "test1", DEVLINK_PARAM_TYPE_BOOL,
429150e8f8aSJiri Pirko 			     BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
430150e8f8aSJiri Pirko 			     NULL, NULL, NULL),
431150e8f8aSJiri Pirko };
432150e8f8aSJiri Pirko 
433150e8f8aSJiri Pirko static void nsim_devlink_set_params_init_values(struct nsim_dev *nsim_dev,
434150e8f8aSJiri Pirko 						struct devlink *devlink)
435150e8f8aSJiri Pirko {
436150e8f8aSJiri Pirko 	union devlink_param_value value;
437150e8f8aSJiri Pirko 
438150e8f8aSJiri Pirko 	value.vu32 = nsim_dev->max_macs;
439150e8f8aSJiri Pirko 	devlink_param_driverinit_value_set(devlink,
440150e8f8aSJiri Pirko 					   DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
441150e8f8aSJiri Pirko 					   value);
442150e8f8aSJiri Pirko 	value.vbool = nsim_dev->test1;
443150e8f8aSJiri Pirko 	devlink_param_driverinit_value_set(devlink,
444150e8f8aSJiri Pirko 					   NSIM_DEVLINK_PARAM_ID_TEST1,
445150e8f8aSJiri Pirko 					   value);
446150e8f8aSJiri Pirko }
447150e8f8aSJiri Pirko 
448150e8f8aSJiri Pirko static void nsim_devlink_param_load_driverinit_values(struct devlink *devlink)
449150e8f8aSJiri Pirko {
450150e8f8aSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
451150e8f8aSJiri Pirko 	union devlink_param_value saved_value;
452150e8f8aSJiri Pirko 	int err;
453150e8f8aSJiri Pirko 
454150e8f8aSJiri Pirko 	err = devlink_param_driverinit_value_get(devlink,
455150e8f8aSJiri Pirko 						 DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
456150e8f8aSJiri Pirko 						 &saved_value);
457150e8f8aSJiri Pirko 	if (!err)
458150e8f8aSJiri Pirko 		nsim_dev->max_macs = saved_value.vu32;
459150e8f8aSJiri Pirko 	err = devlink_param_driverinit_value_get(devlink,
460150e8f8aSJiri Pirko 						 NSIM_DEVLINK_PARAM_ID_TEST1,
461150e8f8aSJiri Pirko 						 &saved_value);
462150e8f8aSJiri Pirko 	if (!err)
463150e8f8aSJiri Pirko 		nsim_dev->test1 = saved_value.vbool;
464150e8f8aSJiri Pirko }
465150e8f8aSJiri Pirko 
4664418f862SJiri Pirko #define NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX 16
4674418f862SJiri Pirko 
468e8937681SJacob Keller static const struct devlink_region_ops dummy_region_ops = {
469e8937681SJacob Keller 	.name = "dummy",
470a0a09f6bSJacob Keller 	.destructor = &kfree,
4713fe0fd53SJacob Keller 	.snapshot = nsim_dev_take_snapshot,
472e8937681SJacob Keller };
473e8937681SJacob Keller 
4744418f862SJiri Pirko static int nsim_dev_dummy_region_init(struct nsim_dev *nsim_dev,
4754418f862SJiri Pirko 				      struct devlink *devlink)
4764418f862SJiri Pirko {
4774418f862SJiri Pirko 	nsim_dev->dummy_region =
478e8937681SJacob Keller 		devlink_region_create(devlink, &dummy_region_ops,
4794418f862SJiri Pirko 				      NSIM_DEV_DUMMY_REGION_SNAPSHOT_MAX,
4804418f862SJiri Pirko 				      NSIM_DEV_DUMMY_REGION_SIZE);
4814418f862SJiri Pirko 	return PTR_ERR_OR_ZERO(nsim_dev->dummy_region);
4824418f862SJiri Pirko }
4834418f862SJiri Pirko 
4844418f862SJiri Pirko static void nsim_dev_dummy_region_exit(struct nsim_dev *nsim_dev)
4854418f862SJiri Pirko {
4864418f862SJiri Pirko 	devlink_region_destroy(nsim_dev->dummy_region);
4874418f862SJiri Pirko }
4884418f862SJiri Pirko 
489160dc373SDmytro Linkin static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port);
490160dc373SDmytro Linkin int nsim_esw_legacy_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack)
491160dc373SDmytro Linkin {
492885226f5SDmytro Linkin 	struct devlink *devlink = priv_to_devlink(nsim_dev);
493160dc373SDmytro Linkin 	struct nsim_dev_port *nsim_dev_port, *tmp;
494160dc373SDmytro Linkin 
495885226f5SDmytro Linkin 	devlink_rate_nodes_destroy(devlink);
496160dc373SDmytro Linkin 	mutex_lock(&nsim_dev->port_list_lock);
497160dc373SDmytro Linkin 	list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list)
498160dc373SDmytro Linkin 		if (nsim_dev_port_is_vf(nsim_dev_port))
499160dc373SDmytro Linkin 			__nsim_dev_port_del(nsim_dev_port);
500160dc373SDmytro Linkin 	mutex_unlock(&nsim_dev->port_list_lock);
501160dc373SDmytro Linkin 	nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY;
502160dc373SDmytro Linkin 	return 0;
503160dc373SDmytro Linkin }
504160dc373SDmytro Linkin 
505160dc373SDmytro Linkin int nsim_esw_switchdev_enable(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack)
506160dc373SDmytro Linkin {
507160dc373SDmytro Linkin 	struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev;
508160dc373SDmytro Linkin 	int i, err;
509160dc373SDmytro Linkin 
510160dc373SDmytro Linkin 	for (i = 0; i < nsim_bus_dev->num_vfs; i++) {
511160dc373SDmytro Linkin 		err = nsim_dev_port_add(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i);
512160dc373SDmytro Linkin 		if (err) {
513160dc373SDmytro Linkin 			NL_SET_ERR_MSG_MOD(extack, "Failed to initialize VFs' netdevsim ports");
514160dc373SDmytro Linkin 			pr_err("Failed to initialize VF id=%d. %d.\n", i, err);
515160dc373SDmytro Linkin 			goto err_port_add_vfs;
516160dc373SDmytro Linkin 		}
517160dc373SDmytro Linkin 	}
518160dc373SDmytro Linkin 	nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
519160dc373SDmytro Linkin 	return 0;
520160dc373SDmytro Linkin 
521160dc373SDmytro Linkin err_port_add_vfs:
522160dc373SDmytro Linkin 	for (i--; i >= 0; i--)
523160dc373SDmytro Linkin 		nsim_dev_port_del(nsim_bus_dev, NSIM_DEV_PORT_TYPE_VF, i);
524160dc373SDmytro Linkin 	return err;
525160dc373SDmytro Linkin }
526160dc373SDmytro Linkin 
527160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
528160dc373SDmytro Linkin 					 struct netlink_ext_ack *extack)
529160dc373SDmytro Linkin {
530160dc373SDmytro Linkin 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
531160dc373SDmytro Linkin 	int err = 0;
532160dc373SDmytro Linkin 
533160dc373SDmytro Linkin 	mutex_lock(&nsim_dev->nsim_bus_dev->vfs_lock);
534160dc373SDmytro Linkin 	if (mode == nsim_dev->esw_mode)
535160dc373SDmytro Linkin 		goto unlock;
536160dc373SDmytro Linkin 
537160dc373SDmytro Linkin 	if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
538160dc373SDmytro Linkin 		err = nsim_esw_legacy_enable(nsim_dev, extack);
539160dc373SDmytro Linkin 	else if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
540160dc373SDmytro Linkin 		err = nsim_esw_switchdev_enable(nsim_dev, extack);
541160dc373SDmytro Linkin 	else
542160dc373SDmytro Linkin 		err = -EINVAL;
543160dc373SDmytro Linkin 
544160dc373SDmytro Linkin unlock:
545160dc373SDmytro Linkin 	mutex_unlock(&nsim_dev->nsim_bus_dev->vfs_lock);
546160dc373SDmytro Linkin 	return err;
547160dc373SDmytro Linkin }
548160dc373SDmytro Linkin 
549160dc373SDmytro Linkin static int nsim_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
550160dc373SDmytro Linkin {
551160dc373SDmytro Linkin 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
552160dc373SDmytro Linkin 
553160dc373SDmytro Linkin 	*mode = nsim_dev->esw_mode;
554160dc373SDmytro Linkin 	return 0;
555160dc373SDmytro Linkin }
556160dc373SDmytro Linkin 
557da58f90fSIdo Schimmel struct nsim_trap_item {
558da58f90fSIdo Schimmel 	void *trap_ctx;
559da58f90fSIdo Schimmel 	enum devlink_trap_action action;
560da58f90fSIdo Schimmel };
561da58f90fSIdo Schimmel 
562da58f90fSIdo Schimmel struct nsim_trap_data {
563da58f90fSIdo Schimmel 	struct delayed_work trap_report_dw;
564da58f90fSIdo Schimmel 	struct nsim_trap_item *trap_items_arr;
565ad188458SIdo Schimmel 	u64 *trap_policers_cnt_arr;
566da58f90fSIdo Schimmel 	struct nsim_dev *nsim_dev;
567da58f90fSIdo Schimmel 	spinlock_t trap_lock;	/* Protects trap_items_arr */
568da58f90fSIdo Schimmel };
569da58f90fSIdo Schimmel 
5709e087457SIdo Schimmel /* All driver-specific traps must be documented in
57104e4272cSJacob Keller  * Documentation/networking/devlink/netdevsim.rst
5729e087457SIdo Schimmel  */
573da58f90fSIdo Schimmel enum {
574da58f90fSIdo Schimmel 	NSIM_TRAP_ID_BASE = DEVLINK_TRAP_GENERIC_ID_MAX,
575da58f90fSIdo Schimmel 	NSIM_TRAP_ID_FID_MISS,
576da58f90fSIdo Schimmel };
577da58f90fSIdo Schimmel 
578da58f90fSIdo Schimmel #define NSIM_TRAP_NAME_FID_MISS "fid_miss"
579da58f90fSIdo Schimmel 
580da58f90fSIdo Schimmel #define NSIM_TRAP_METADATA DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT
581da58f90fSIdo Schimmel 
582da58f90fSIdo Schimmel #define NSIM_TRAP_DROP(_id, _group_id)					      \
583da58f90fSIdo Schimmel 	DEVLINK_TRAP_GENERIC(DROP, DROP, _id,				      \
584107f1678SIdo Schimmel 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
585da58f90fSIdo Schimmel 			     NSIM_TRAP_METADATA)
586d3cbb907SJiri Pirko #define NSIM_TRAP_DROP_EXT(_id, _group_id, _metadata)			      \
587d3cbb907SJiri Pirko 	DEVLINK_TRAP_GENERIC(DROP, DROP, _id,				      \
588107f1678SIdo Schimmel 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
589d3cbb907SJiri Pirko 			     NSIM_TRAP_METADATA | (_metadata))
590da58f90fSIdo Schimmel #define NSIM_TRAP_EXCEPTION(_id, _group_id)				      \
591da58f90fSIdo Schimmel 	DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id,			      \
592107f1678SIdo Schimmel 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
593da58f90fSIdo Schimmel 			     NSIM_TRAP_METADATA)
59418979367SIdo Schimmel #define NSIM_TRAP_CONTROL(_id, _group_id, _action)			      \
59518979367SIdo Schimmel 	DEVLINK_TRAP_GENERIC(CONTROL, _action, _id,			      \
59618979367SIdo Schimmel 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
59718979367SIdo Schimmel 			     NSIM_TRAP_METADATA)
598da58f90fSIdo Schimmel #define NSIM_TRAP_DRIVER_EXCEPTION(_id, _group_id)			      \
599da58f90fSIdo Schimmel 	DEVLINK_TRAP_DRIVER(EXCEPTION, TRAP, NSIM_TRAP_ID_##_id,	      \
600da58f90fSIdo Schimmel 			    NSIM_TRAP_NAME_##_id,			      \
601107f1678SIdo Schimmel 			    DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id,	      \
602da58f90fSIdo Schimmel 			    NSIM_TRAP_METADATA)
603da58f90fSIdo Schimmel 
604ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_RATE	1
605ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_RATE	8000
606ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MIN_BURST	8
607ad188458SIdo Schimmel #define NSIM_DEV_TRAP_POLICER_MAX_BURST	65536
608ad188458SIdo Schimmel 
609ad188458SIdo Schimmel #define NSIM_TRAP_POLICER(_id, _rate, _burst)				      \
610ad188458SIdo Schimmel 	DEVLINK_TRAP_POLICER(_id, _rate, _burst,			      \
611ad188458SIdo Schimmel 			     NSIM_DEV_TRAP_POLICER_MAX_RATE,		      \
612ad188458SIdo Schimmel 			     NSIM_DEV_TRAP_POLICER_MIN_RATE,		      \
613ad188458SIdo Schimmel 			     NSIM_DEV_TRAP_POLICER_MAX_BURST,		      \
614ad188458SIdo Schimmel 			     NSIM_DEV_TRAP_POLICER_MIN_BURST)
615ad188458SIdo Schimmel 
616ad188458SIdo Schimmel static const struct devlink_trap_policer nsim_trap_policers_arr[] = {
617ad188458SIdo Schimmel 	NSIM_TRAP_POLICER(1, 1000, 128),
618ad188458SIdo Schimmel 	NSIM_TRAP_POLICER(2, 2000, 256),
619ad188458SIdo Schimmel 	NSIM_TRAP_POLICER(3, 3000, 512),
620ad188458SIdo Schimmel };
621ad188458SIdo Schimmel 
622b29545d8SIdo Schimmel static const struct devlink_trap_group nsim_trap_groups_arr[] = {
623f9f54392SIdo Schimmel 	DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0),
624f9f54392SIdo Schimmel 	DEVLINK_TRAP_GROUP_GENERIC(L3_DROPS, 1),
62585176f19SIdo Schimmel 	DEVLINK_TRAP_GROUP_GENERIC(L3_EXCEPTIONS, 1),
626f9f54392SIdo Schimmel 	DEVLINK_TRAP_GROUP_GENERIC(BUFFER_DROPS, 2),
627f9f54392SIdo Schimmel 	DEVLINK_TRAP_GROUP_GENERIC(ACL_DROPS, 3),
62818979367SIdo Schimmel 	DEVLINK_TRAP_GROUP_GENERIC(MC_SNOOPING, 3),
629b29545d8SIdo Schimmel };
630b29545d8SIdo Schimmel 
631da58f90fSIdo Schimmel static const struct devlink_trap nsim_traps_arr[] = {
632da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(SMAC_MC, L2_DROPS),
633da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS),
634da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
635da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS),
636da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS),
637da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS),
638da58f90fSIdo Schimmel 	NSIM_TRAP_DRIVER_EXCEPTION(FID_MISS, L2_DROPS),
639da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS),
64085176f19SIdo Schimmel 	NSIM_TRAP_EXCEPTION(TTL_ERROR, L3_EXCEPTIONS),
641da58f90fSIdo Schimmel 	NSIM_TRAP_DROP(TAIL_DROP, BUFFER_DROPS),
642d3cbb907SJiri Pirko 	NSIM_TRAP_DROP_EXT(INGRESS_FLOW_ACTION_DROP, ACL_DROPS,
643d3cbb907SJiri Pirko 			   DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
644d3cbb907SJiri Pirko 	NSIM_TRAP_DROP_EXT(EGRESS_FLOW_ACTION_DROP, ACL_DROPS,
645d3cbb907SJiri Pirko 			   DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE),
64618979367SIdo Schimmel 	NSIM_TRAP_CONTROL(IGMP_QUERY, MC_SNOOPING, MIRROR),
64718979367SIdo Schimmel 	NSIM_TRAP_CONTROL(IGMP_V1_REPORT, MC_SNOOPING, TRAP),
648da58f90fSIdo Schimmel };
649da58f90fSIdo Schimmel 
650da58f90fSIdo Schimmel #define NSIM_TRAP_L4_DATA_LEN 100
651da58f90fSIdo Schimmel 
652da58f90fSIdo Schimmel static struct sk_buff *nsim_dev_trap_skb_build(void)
653da58f90fSIdo Schimmel {
654da58f90fSIdo Schimmel 	int tot_len, data_len = NSIM_TRAP_L4_DATA_LEN;
655da58f90fSIdo Schimmel 	struct sk_buff *skb;
656da58f90fSIdo Schimmel 	struct udphdr *udph;
657da58f90fSIdo Schimmel 	struct ethhdr *eth;
658da58f90fSIdo Schimmel 	struct iphdr *iph;
659da58f90fSIdo Schimmel 
660da58f90fSIdo Schimmel 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
661da58f90fSIdo Schimmel 	if (!skb)
662da58f90fSIdo Schimmel 		return NULL;
663da58f90fSIdo Schimmel 	tot_len = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len;
664da58f90fSIdo Schimmel 
66558a406deSIdo Schimmel 	skb_reset_mac_header(skb);
666da58f90fSIdo Schimmel 	eth = skb_put(skb, sizeof(struct ethhdr));
667da58f90fSIdo Schimmel 	eth_random_addr(eth->h_dest);
668da58f90fSIdo Schimmel 	eth_random_addr(eth->h_source);
669da58f90fSIdo Schimmel 	eth->h_proto = htons(ETH_P_IP);
670da58f90fSIdo Schimmel 	skb->protocol = htons(ETH_P_IP);
671da58f90fSIdo Schimmel 
67258a406deSIdo Schimmel 	skb_set_network_header(skb, skb->len);
673da58f90fSIdo Schimmel 	iph = skb_put(skb, sizeof(struct iphdr));
674da58f90fSIdo Schimmel 	iph->protocol = IPPROTO_UDP;
675da58f90fSIdo Schimmel 	iph->saddr = in_aton("192.0.2.1");
676da58f90fSIdo Schimmel 	iph->daddr = in_aton("198.51.100.1");
677da58f90fSIdo Schimmel 	iph->version = 0x4;
678da58f90fSIdo Schimmel 	iph->frag_off = 0;
679da58f90fSIdo Schimmel 	iph->ihl = 0x5;
680da58f90fSIdo Schimmel 	iph->tot_len = htons(tot_len);
681da58f90fSIdo Schimmel 	iph->ttl = 100;
682d9bd6d27SYueHaibing 	iph->check = 0;
683d9bd6d27SYueHaibing 	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
684da58f90fSIdo Schimmel 
68558a406deSIdo Schimmel 	skb_set_transport_header(skb, skb->len);
686da58f90fSIdo Schimmel 	udph = skb_put_zero(skb, sizeof(struct udphdr) + data_len);
687da58f90fSIdo Schimmel 	get_random_bytes(&udph->source, sizeof(u16));
688da58f90fSIdo Schimmel 	get_random_bytes(&udph->dest, sizeof(u16));
689da58f90fSIdo Schimmel 	udph->len = htons(sizeof(struct udphdr) + data_len);
690da58f90fSIdo Schimmel 
691da58f90fSIdo Schimmel 	return skb;
692da58f90fSIdo Schimmel }
693da58f90fSIdo Schimmel 
694da58f90fSIdo Schimmel static void nsim_dev_trap_report(struct nsim_dev_port *nsim_dev_port)
695da58f90fSIdo Schimmel {
696da58f90fSIdo Schimmel 	struct nsim_dev *nsim_dev = nsim_dev_port->ns->nsim_dev;
697da58f90fSIdo Schimmel 	struct devlink *devlink = priv_to_devlink(nsim_dev);
698da58f90fSIdo Schimmel 	struct nsim_trap_data *nsim_trap_data;
699da58f90fSIdo Schimmel 	int i;
700da58f90fSIdo Schimmel 
701da58f90fSIdo Schimmel 	nsim_trap_data = nsim_dev->trap_data;
702da58f90fSIdo Schimmel 
703da58f90fSIdo Schimmel 	spin_lock(&nsim_trap_data->trap_lock);
704da58f90fSIdo Schimmel 	for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {
705d3cbb907SJiri Pirko 		struct flow_action_cookie *fa_cookie = NULL;
706da58f90fSIdo Schimmel 		struct nsim_trap_item *nsim_trap_item;
707da58f90fSIdo Schimmel 		struct sk_buff *skb;
708d3cbb907SJiri Pirko 		bool has_fa_cookie;
709d3cbb907SJiri Pirko 
710d3cbb907SJiri Pirko 		has_fa_cookie = nsim_traps_arr[i].metadata_cap &
711d3cbb907SJiri Pirko 				DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE;
712da58f90fSIdo Schimmel 
713da58f90fSIdo Schimmel 		nsim_trap_item = &nsim_trap_data->trap_items_arr[i];
714da58f90fSIdo Schimmel 		if (nsim_trap_item->action == DEVLINK_TRAP_ACTION_DROP)
715da58f90fSIdo Schimmel 			continue;
716da58f90fSIdo Schimmel 
717da58f90fSIdo Schimmel 		skb = nsim_dev_trap_skb_build();
718da58f90fSIdo Schimmel 		if (!skb)
719da58f90fSIdo Schimmel 			continue;
720da58f90fSIdo Schimmel 		skb->dev = nsim_dev_port->ns->netdev;
721da58f90fSIdo Schimmel 
722da58f90fSIdo Schimmel 		/* Trapped packets are usually passed to devlink in softIRQ,
723da58f90fSIdo Schimmel 		 * but in this case they are generated in a workqueue. Disable
724da58f90fSIdo Schimmel 		 * softIRQs to prevent lockdep from complaining about
725da58f90fSIdo Schimmel 		 * "incosistent lock state".
726da58f90fSIdo Schimmel 		 */
727d3cbb907SJiri Pirko 
728d3cbb907SJiri Pirko 		spin_lock_bh(&nsim_dev->fa_cookie_lock);
729d3cbb907SJiri Pirko 		fa_cookie = has_fa_cookie ? nsim_dev->fa_cookie : NULL;
730da58f90fSIdo Schimmel 		devlink_trap_report(devlink, skb, nsim_trap_item->trap_ctx,
731d3cbb907SJiri Pirko 				    &nsim_dev_port->devlink_port, fa_cookie);
732d3cbb907SJiri Pirko 		spin_unlock_bh(&nsim_dev->fa_cookie_lock);
733da58f90fSIdo Schimmel 		consume_skb(skb);
734da58f90fSIdo Schimmel 	}
735da58f90fSIdo Schimmel 	spin_unlock(&nsim_trap_data->trap_lock);
736da58f90fSIdo Schimmel }
737da58f90fSIdo Schimmel 
738da58f90fSIdo Schimmel #define NSIM_TRAP_REPORT_INTERVAL_MS	100
739da58f90fSIdo Schimmel 
740da58f90fSIdo Schimmel static void nsim_dev_trap_report_work(struct work_struct *work)
741da58f90fSIdo Schimmel {
742da58f90fSIdo Schimmel 	struct nsim_trap_data *nsim_trap_data;
743da58f90fSIdo Schimmel 	struct nsim_dev_port *nsim_dev_port;
744da58f90fSIdo Schimmel 	struct nsim_dev *nsim_dev;
745da58f90fSIdo Schimmel 
746da58f90fSIdo Schimmel 	nsim_trap_data = container_of(work, struct nsim_trap_data,
747da58f90fSIdo Schimmel 				      trap_report_dw.work);
748da58f90fSIdo Schimmel 	nsim_dev = nsim_trap_data->nsim_dev;
749da58f90fSIdo Schimmel 
750da58f90fSIdo Schimmel 	/* For each running port and enabled packet trap, generate a UDP
751da58f90fSIdo Schimmel 	 * packet with a random 5-tuple and report it.
752da58f90fSIdo Schimmel 	 */
753da58f90fSIdo Schimmel 	mutex_lock(&nsim_dev->port_list_lock);
754da58f90fSIdo Schimmel 	list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) {
755da58f90fSIdo Schimmel 		if (!netif_running(nsim_dev_port->ns->netdev))
756da58f90fSIdo Schimmel 			continue;
757da58f90fSIdo Schimmel 
758da58f90fSIdo Schimmel 		nsim_dev_trap_report(nsim_dev_port);
759da58f90fSIdo Schimmel 	}
760da58f90fSIdo Schimmel 	mutex_unlock(&nsim_dev->port_list_lock);
761da58f90fSIdo Schimmel 
762da58f90fSIdo Schimmel 	schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw,
763da58f90fSIdo Schimmel 			      msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS));
764da58f90fSIdo Schimmel }
765da58f90fSIdo Schimmel 
766da58f90fSIdo Schimmel static int nsim_dev_traps_init(struct devlink *devlink)
767da58f90fSIdo Schimmel {
768ad188458SIdo Schimmel 	size_t policers_count = ARRAY_SIZE(nsim_trap_policers_arr);
769da58f90fSIdo Schimmel 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
770da58f90fSIdo Schimmel 	struct nsim_trap_data *nsim_trap_data;
771da58f90fSIdo Schimmel 	int err;
772da58f90fSIdo Schimmel 
773da58f90fSIdo Schimmel 	nsim_trap_data = kzalloc(sizeof(*nsim_trap_data), GFP_KERNEL);
774da58f90fSIdo Schimmel 	if (!nsim_trap_data)
775da58f90fSIdo Schimmel 		return -ENOMEM;
776da58f90fSIdo Schimmel 
777da58f90fSIdo Schimmel 	nsim_trap_data->trap_items_arr = kcalloc(ARRAY_SIZE(nsim_traps_arr),
778da58f90fSIdo Schimmel 						 sizeof(struct nsim_trap_item),
779da58f90fSIdo Schimmel 						 GFP_KERNEL);
780da58f90fSIdo Schimmel 	if (!nsim_trap_data->trap_items_arr) {
781da58f90fSIdo Schimmel 		err = -ENOMEM;
782da58f90fSIdo Schimmel 		goto err_trap_data_free;
783da58f90fSIdo Schimmel 	}
784da58f90fSIdo Schimmel 
785ad188458SIdo Schimmel 	nsim_trap_data->trap_policers_cnt_arr = kcalloc(policers_count,
786ad188458SIdo Schimmel 							sizeof(u64),
787ad188458SIdo Schimmel 							GFP_KERNEL);
788ad188458SIdo Schimmel 	if (!nsim_trap_data->trap_policers_cnt_arr) {
789ad188458SIdo Schimmel 		err = -ENOMEM;
790ad188458SIdo Schimmel 		goto err_trap_items_free;
791ad188458SIdo Schimmel 	}
792ad188458SIdo Schimmel 
793da58f90fSIdo Schimmel 	/* The lock is used to protect the action state of the registered
794da58f90fSIdo Schimmel 	 * traps. The value is written by user and read in delayed work when
795da58f90fSIdo Schimmel 	 * iterating over all the traps.
796da58f90fSIdo Schimmel 	 */
797da58f90fSIdo Schimmel 	spin_lock_init(&nsim_trap_data->trap_lock);
798da58f90fSIdo Schimmel 	nsim_trap_data->nsim_dev = nsim_dev;
799da58f90fSIdo Schimmel 	nsim_dev->trap_data = nsim_trap_data;
800da58f90fSIdo Schimmel 
801ad188458SIdo Schimmel 	err = devlink_trap_policers_register(devlink, nsim_trap_policers_arr,
802ad188458SIdo Schimmel 					     policers_count);
803ad188458SIdo Schimmel 	if (err)
804ad188458SIdo Schimmel 		goto err_trap_policers_cnt_free;
805ad188458SIdo Schimmel 
806b29545d8SIdo Schimmel 	err = devlink_trap_groups_register(devlink, nsim_trap_groups_arr,
807b29545d8SIdo Schimmel 					   ARRAY_SIZE(nsim_trap_groups_arr));
808b29545d8SIdo Schimmel 	if (err)
809ad188458SIdo Schimmel 		goto err_trap_policers_unregister;
810b29545d8SIdo Schimmel 
811da58f90fSIdo Schimmel 	err = devlink_traps_register(devlink, nsim_traps_arr,
812da58f90fSIdo Schimmel 				     ARRAY_SIZE(nsim_traps_arr), NULL);
813da58f90fSIdo Schimmel 	if (err)
814b29545d8SIdo Schimmel 		goto err_trap_groups_unregister;
815da58f90fSIdo Schimmel 
816da58f90fSIdo Schimmel 	INIT_DELAYED_WORK(&nsim_dev->trap_data->trap_report_dw,
817da58f90fSIdo Schimmel 			  nsim_dev_trap_report_work);
818da58f90fSIdo Schimmel 	schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw,
819da58f90fSIdo Schimmel 			      msecs_to_jiffies(NSIM_TRAP_REPORT_INTERVAL_MS));
820da58f90fSIdo Schimmel 
821da58f90fSIdo Schimmel 	return 0;
822da58f90fSIdo Schimmel 
823b29545d8SIdo Schimmel err_trap_groups_unregister:
824b29545d8SIdo Schimmel 	devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr,
825b29545d8SIdo Schimmel 				       ARRAY_SIZE(nsim_trap_groups_arr));
826ad188458SIdo Schimmel err_trap_policers_unregister:
827ad188458SIdo Schimmel 	devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr,
828ad188458SIdo Schimmel 					 ARRAY_SIZE(nsim_trap_policers_arr));
829ad188458SIdo Schimmel err_trap_policers_cnt_free:
830ad188458SIdo Schimmel 	kfree(nsim_trap_data->trap_policers_cnt_arr);
831da58f90fSIdo Schimmel err_trap_items_free:
832da58f90fSIdo Schimmel 	kfree(nsim_trap_data->trap_items_arr);
833da58f90fSIdo Schimmel err_trap_data_free:
834da58f90fSIdo Schimmel 	kfree(nsim_trap_data);
835da58f90fSIdo Schimmel 	return err;
836da58f90fSIdo Schimmel }
837da58f90fSIdo Schimmel 
838da58f90fSIdo Schimmel static void nsim_dev_traps_exit(struct devlink *devlink)
839da58f90fSIdo Schimmel {
840da58f90fSIdo Schimmel 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
841da58f90fSIdo Schimmel 
842da58f90fSIdo Schimmel 	cancel_delayed_work_sync(&nsim_dev->trap_data->trap_report_dw);
843da58f90fSIdo Schimmel 	devlink_traps_unregister(devlink, nsim_traps_arr,
844da58f90fSIdo Schimmel 				 ARRAY_SIZE(nsim_traps_arr));
845b29545d8SIdo Schimmel 	devlink_trap_groups_unregister(devlink, nsim_trap_groups_arr,
846b29545d8SIdo Schimmel 				       ARRAY_SIZE(nsim_trap_groups_arr));
847ad188458SIdo Schimmel 	devlink_trap_policers_unregister(devlink, nsim_trap_policers_arr,
848ad188458SIdo Schimmel 					 ARRAY_SIZE(nsim_trap_policers_arr));
849ad188458SIdo Schimmel 	kfree(nsim_dev->trap_data->trap_policers_cnt_arr);
850da58f90fSIdo Schimmel 	kfree(nsim_dev->trap_data->trap_items_arr);
851da58f90fSIdo Schimmel 	kfree(nsim_dev->trap_data);
852da58f90fSIdo Schimmel }
853da58f90fSIdo Schimmel 
85475ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev,
85575ba029fSJiri Pirko 				  struct netlink_ext_ack *extack);
85675ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev);
85775ba029fSJiri Pirko 
858070c63f2SJiri Pirko static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change,
859dc64cc7cSMoshe Shemesh 				enum devlink_reload_action action, enum devlink_reload_limit limit,
860dc64cc7cSMoshe Shemesh 				struct netlink_ext_ack *extack)
86197691069SJiri Pirko {
86275ba029fSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
86375ba029fSJiri Pirko 
864155ddfc5SJiri Pirko 	if (nsim_dev->dont_allow_reload) {
865155ddfc5SJiri Pirko 		/* For testing purposes, user set debugfs dont_allow_reload
866155ddfc5SJiri Pirko 		 * value to true. So forbid it.
867155ddfc5SJiri Pirko 		 */
868f9867b51SColin Ian King 		NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes");
869155ddfc5SJiri Pirko 		return -EOPNOTSUPP;
870155ddfc5SJiri Pirko 	}
871155ddfc5SJiri Pirko 
87275ba029fSJiri Pirko 	nsim_dev_reload_destroy(nsim_dev);
87397691069SJiri Pirko 	return 0;
87497691069SJiri Pirko }
87597691069SJiri Pirko 
876ccdf0721SMoshe Shemesh static int nsim_dev_reload_up(struct devlink *devlink, enum devlink_reload_action action,
877dc64cc7cSMoshe Shemesh 			      enum devlink_reload_limit limit, u32 *actions_performed,
878dc64cc7cSMoshe Shemesh 			      struct netlink_ext_ack *extack)
8798fb4bc6fSJiri Pirko {
880a5facc4cSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
8818fb4bc6fSJiri Pirko 
882155ddfc5SJiri Pirko 	if (nsim_dev->fail_reload) {
883155ddfc5SJiri Pirko 		/* For testing purposes, user set debugfs fail_reload
884155ddfc5SJiri Pirko 		 * value to true. Fail right away.
885155ddfc5SJiri Pirko 		 */
886155ddfc5SJiri Pirko 		NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes");
887155ddfc5SJiri Pirko 		return -EINVAL;
888155ddfc5SJiri Pirko 	}
889155ddfc5SJiri Pirko 
890ccdf0721SMoshe Shemesh 	*actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
89175ba029fSJiri Pirko 	return nsim_dev_reload_create(nsim_dev, extack);
8928fb4bc6fSJiri Pirko }
8938fb4bc6fSJiri Pirko 
8948e23cc03SJiri Pirko static int nsim_dev_info_get(struct devlink *devlink,
8958e23cc03SJiri Pirko 			     struct devlink_info_req *req,
8968e23cc03SJiri Pirko 			     struct netlink_ext_ack *extack)
8978e23cc03SJiri Pirko {
8988e23cc03SJiri Pirko 	return devlink_info_driver_name_put(req, DRV_NAME);
8998e23cc03SJiri Pirko }
9008e23cc03SJiri Pirko 
901fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_SIZE 500000
902fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_SIZE 1000
903fa4dfc4aSJiri Pirko #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10
904fa4dfc4aSJiri Pirko 
905bc75c054SJacob Keller static int nsim_dev_flash_update(struct devlink *devlink,
906bc75c054SJacob Keller 				 struct devlink_flash_update_params *params,
907fa4dfc4aSJiri Pirko 				 struct netlink_ext_ack *extack)
908fa4dfc4aSJiri Pirko {
909fa4dfc4aSJiri Pirko 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
910fa4dfc4aSJiri Pirko 	int i;
911fa4dfc4aSJiri Pirko 
912cbb58368SJacob Keller 	if ((params->overwrite_mask & ~nsim_dev->fw_update_overwrite_mask) != 0)
913cbb58368SJacob Keller 		return -EOPNOTSUPP;
914cbb58368SJacob Keller 
915fa4dfc4aSJiri Pirko 	if (nsim_dev->fw_update_status) {
916fa4dfc4aSJiri Pirko 		devlink_flash_update_status_notify(devlink,
917fa4dfc4aSJiri Pirko 						   "Preparing to flash",
918bc75c054SJacob Keller 						   params->component, 0, 0);
919fa4dfc4aSJiri Pirko 	}
920fa4dfc4aSJiri Pirko 
921fa4dfc4aSJiri Pirko 	for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) {
922fa4dfc4aSJiri Pirko 		if (nsim_dev->fw_update_status)
923fa4dfc4aSJiri Pirko 			devlink_flash_update_status_notify(devlink, "Flashing",
924bc75c054SJacob Keller 							   params->component,
925fa4dfc4aSJiri Pirko 							   i * NSIM_DEV_FLASH_CHUNK_SIZE,
926fa4dfc4aSJiri Pirko 							   NSIM_DEV_FLASH_SIZE);
927fa4dfc4aSJiri Pirko 		msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS);
928fa4dfc4aSJiri Pirko 	}
929fa4dfc4aSJiri Pirko 
930fa4dfc4aSJiri Pirko 	if (nsim_dev->fw_update_status) {
931fa4dfc4aSJiri Pirko 		devlink_flash_update_status_notify(devlink, "Flashing",
932bc75c054SJacob Keller 						   params->component,
933fa4dfc4aSJiri Pirko 						   NSIM_DEV_FLASH_SIZE,
934fa4dfc4aSJiri Pirko 						   NSIM_DEV_FLASH_SIZE);
935b311b001SShannon Nelson 		devlink_flash_update_timeout_notify(devlink, "Flash select",
936bc75c054SJacob Keller 						    params->component, 81);
937fa4dfc4aSJiri Pirko 		devlink_flash_update_status_notify(devlink, "Flashing done",
938bc75c054SJacob Keller 						   params->component, 0, 0);
939fa4dfc4aSJiri Pirko 	}
940fa4dfc4aSJiri Pirko 
941fa4dfc4aSJiri Pirko 	return 0;
942fa4dfc4aSJiri Pirko }
943fa4dfc4aSJiri Pirko 
944da58f90fSIdo Schimmel static struct nsim_trap_item *
945da58f90fSIdo Schimmel nsim_dev_trap_item_lookup(struct nsim_dev *nsim_dev, u16 trap_id)
946da58f90fSIdo Schimmel {
947da58f90fSIdo Schimmel 	struct nsim_trap_data *nsim_trap_data = nsim_dev->trap_data;
948da58f90fSIdo Schimmel 	int i;
949da58f90fSIdo Schimmel 
950da58f90fSIdo Schimmel 	for (i = 0; i < ARRAY_SIZE(nsim_traps_arr); i++) {
951da58f90fSIdo Schimmel 		if (nsim_traps_arr[i].id == trap_id)
952da58f90fSIdo Schimmel 			return &nsim_trap_data->trap_items_arr[i];
953da58f90fSIdo Schimmel 	}
954da58f90fSIdo Schimmel 
955da58f90fSIdo Schimmel 	return NULL;
956da58f90fSIdo Schimmel }
957da58f90fSIdo Schimmel 
958da58f90fSIdo Schimmel static int nsim_dev_devlink_trap_init(struct devlink *devlink,
959da58f90fSIdo Schimmel 				      const struct devlink_trap *trap,
960da58f90fSIdo Schimmel 				      void *trap_ctx)
961da58f90fSIdo Schimmel {
962da58f90fSIdo Schimmel 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
963da58f90fSIdo Schimmel 	struct nsim_trap_item *nsim_trap_item;
964da58f90fSIdo Schimmel 
965da58f90fSIdo Schimmel 	nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);
966da58f90fSIdo Schimmel 	if (WARN_ON(!nsim_trap_item))
967da58f90fSIdo Schimmel 		return -ENOENT;
968da58f90fSIdo Schimmel 
969da58f90fSIdo Schimmel 	nsim_trap_item->trap_ctx = trap_ctx;
970da58f90fSIdo Schimmel 	nsim_trap_item->action = trap->init_action;
971da58f90fSIdo Schimmel 
972da58f90fSIdo Schimmel 	return 0;
973da58f90fSIdo Schimmel }
974da58f90fSIdo Schimmel 
975da58f90fSIdo Schimmel static int
976da58f90fSIdo Schimmel nsim_dev_devlink_trap_action_set(struct devlink *devlink,
977da58f90fSIdo Schimmel 				 const struct devlink_trap *trap,
978c88e11e0SIdo Schimmel 				 enum devlink_trap_action action,
979c88e11e0SIdo Schimmel 				 struct netlink_ext_ack *extack)
980da58f90fSIdo Schimmel {
981da58f90fSIdo Schimmel 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
982da58f90fSIdo Schimmel 	struct nsim_trap_item *nsim_trap_item;
983da58f90fSIdo Schimmel 
984da58f90fSIdo Schimmel 	nsim_trap_item = nsim_dev_trap_item_lookup(nsim_dev, trap->id);
985da58f90fSIdo Schimmel 	if (WARN_ON(!nsim_trap_item))
986da58f90fSIdo Schimmel 		return -ENOENT;
987da58f90fSIdo Schimmel 
988da58f90fSIdo Schimmel 	spin_lock(&nsim_dev->trap_data->trap_lock);
989da58f90fSIdo Schimmel 	nsim_trap_item->action = action;
990da58f90fSIdo Schimmel 	spin_unlock(&nsim_dev->trap_data->trap_lock);
991da58f90fSIdo Schimmel 
992da58f90fSIdo Schimmel 	return 0;
993da58f90fSIdo Schimmel }
994da58f90fSIdo Schimmel 
995ad188458SIdo Schimmel static int
9960dc8249aSIdo Schimmel nsim_dev_devlink_trap_group_set(struct devlink *devlink,
9970dc8249aSIdo Schimmel 				const struct devlink_trap_group *group,
998c88e11e0SIdo Schimmel 				const struct devlink_trap_policer *policer,
999c88e11e0SIdo Schimmel 				struct netlink_ext_ack *extack)
10000dc8249aSIdo Schimmel {
10010dc8249aSIdo Schimmel 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
10020dc8249aSIdo Schimmel 
10030dc8249aSIdo Schimmel 	if (nsim_dev->fail_trap_group_set)
10040dc8249aSIdo Schimmel 		return -EINVAL;
10050dc8249aSIdo Schimmel 
10060dc8249aSIdo Schimmel 	return 0;
10070dc8249aSIdo Schimmel }
10080dc8249aSIdo Schimmel 
10090dc8249aSIdo Schimmel static int
1010ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_set(struct devlink *devlink,
1011ad188458SIdo Schimmel 				  const struct devlink_trap_policer *policer,
1012ad188458SIdo Schimmel 				  u64 rate, u64 burst,
1013ad188458SIdo Schimmel 				  struct netlink_ext_ack *extack)
1014ad188458SIdo Schimmel {
1015ad188458SIdo Schimmel 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
1016ad188458SIdo Schimmel 
1017ad188458SIdo Schimmel 	if (nsim_dev->fail_trap_policer_set) {
1018ad188458SIdo Schimmel 		NL_SET_ERR_MSG_MOD(extack, "User setup the operation to fail for testing purposes");
1019ad188458SIdo Schimmel 		return -EINVAL;
1020ad188458SIdo Schimmel 	}
1021ad188458SIdo Schimmel 
1022ad188458SIdo Schimmel 	return 0;
1023ad188458SIdo Schimmel }
1024ad188458SIdo Schimmel 
1025ad188458SIdo Schimmel static int
1026ad188458SIdo Schimmel nsim_dev_devlink_trap_policer_counter_get(struct devlink *devlink,
1027ad188458SIdo Schimmel 					  const struct devlink_trap_policer *policer,
1028ad188458SIdo Schimmel 					  u64 *p_drops)
1029ad188458SIdo Schimmel {
1030ad188458SIdo Schimmel 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
1031ad188458SIdo Schimmel 	u64 *cnt;
1032ad188458SIdo Schimmel 
1033ad188458SIdo Schimmel 	if (nsim_dev->fail_trap_policer_counter_get)
1034ad188458SIdo Schimmel 		return -EINVAL;
1035ad188458SIdo Schimmel 
1036ad188458SIdo Schimmel 	cnt = &nsim_dev->trap_data->trap_policers_cnt_arr[policer->id - 1];
1037be43224fSIdo Schimmel 	*p_drops = (*cnt)++;
1038ad188458SIdo Schimmel 
1039ad188458SIdo Schimmel 	return 0;
1040ad188458SIdo Schimmel }
1041ad188458SIdo Schimmel 
1042605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_MAX     5000 /* Mbps */
1043605c4f8fSDmytro Linkin #define NSIM_LINK_SPEED_UNIT    125000 /* 1 Mbps given in bytes/sec to avoid
1044605c4f8fSDmytro Linkin 					* u64 overflow during conversion from
1045605c4f8fSDmytro Linkin 					* bytes to bits.
1046605c4f8fSDmytro Linkin 					*/
1047605c4f8fSDmytro Linkin 
1048605c4f8fSDmytro Linkin static int nsim_rate_bytes_to_units(char *name, u64 *rate, struct netlink_ext_ack *extack)
1049605c4f8fSDmytro Linkin {
1050605c4f8fSDmytro Linkin 	u64 val;
1051605c4f8fSDmytro Linkin 	u32 rem;
1052605c4f8fSDmytro Linkin 
1053605c4f8fSDmytro Linkin 	val = div_u64_rem(*rate, NSIM_LINK_SPEED_UNIT, &rem);
1054605c4f8fSDmytro Linkin 	if (rem) {
1055605c4f8fSDmytro Linkin 		pr_err("%s rate value %lluBps not in link speed units of 1Mbps.\n",
1056605c4f8fSDmytro Linkin 		       name, *rate);
1057605c4f8fSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "TX rate value not in link speed units of 1Mbps.");
1058605c4f8fSDmytro Linkin 		return -EINVAL;
1059605c4f8fSDmytro Linkin 	}
1060605c4f8fSDmytro Linkin 
1061605c4f8fSDmytro Linkin 	if (val > NSIM_LINK_SPEED_MAX) {
1062605c4f8fSDmytro Linkin 		pr_err("%s rate value %lluMbps exceed link maximum speed 5000Mbps.\n",
1063605c4f8fSDmytro Linkin 		       name, val);
1064605c4f8fSDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "TX rate value exceed link maximum speed 5000Mbps.");
1065605c4f8fSDmytro Linkin 		return -EINVAL;
1066605c4f8fSDmytro Linkin 	}
1067605c4f8fSDmytro Linkin 	*rate = val;
1068605c4f8fSDmytro Linkin 	return 0;
1069605c4f8fSDmytro Linkin }
1070605c4f8fSDmytro Linkin 
1071605c4f8fSDmytro Linkin static int nsim_leaf_tx_share_set(struct devlink_rate *devlink_rate, void *priv,
1072605c4f8fSDmytro Linkin 				  u64 tx_share, struct netlink_ext_ack *extack)
1073605c4f8fSDmytro Linkin {
1074605c4f8fSDmytro Linkin 	struct nsim_dev_port *nsim_dev_port = priv;
1075605c4f8fSDmytro Linkin 	struct nsim_bus_dev *nsim_bus_dev = nsim_dev_port->ns->nsim_bus_dev;
1076605c4f8fSDmytro Linkin 	int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index);
1077605c4f8fSDmytro Linkin 	int err;
1078605c4f8fSDmytro Linkin 
1079605c4f8fSDmytro Linkin 	err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack);
1080605c4f8fSDmytro Linkin 	if (err)
1081605c4f8fSDmytro Linkin 		return err;
1082605c4f8fSDmytro Linkin 
1083605c4f8fSDmytro Linkin 	nsim_bus_dev->vfconfigs[vf_id].min_tx_rate = tx_share;
1084605c4f8fSDmytro Linkin 	return 0;
1085605c4f8fSDmytro Linkin }
1086605c4f8fSDmytro Linkin 
1087605c4f8fSDmytro Linkin static int nsim_leaf_tx_max_set(struct devlink_rate *devlink_rate, void *priv,
1088605c4f8fSDmytro Linkin 				u64 tx_max, struct netlink_ext_ack *extack)
1089605c4f8fSDmytro Linkin {
1090605c4f8fSDmytro Linkin 	struct nsim_dev_port *nsim_dev_port = priv;
1091605c4f8fSDmytro Linkin 	struct nsim_bus_dev *nsim_bus_dev = nsim_dev_port->ns->nsim_bus_dev;
1092605c4f8fSDmytro Linkin 	int vf_id = nsim_dev_port_index_to_vf_index(nsim_dev_port->port_index);
1093605c4f8fSDmytro Linkin 	int err;
1094605c4f8fSDmytro Linkin 
1095605c4f8fSDmytro Linkin 	err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack);
1096605c4f8fSDmytro Linkin 	if (err)
1097605c4f8fSDmytro Linkin 		return err;
1098605c4f8fSDmytro Linkin 
1099605c4f8fSDmytro Linkin 	nsim_bus_dev->vfconfigs[vf_id].max_tx_rate = tx_max;
1100605c4f8fSDmytro Linkin 	return 0;
1101605c4f8fSDmytro Linkin }
1102605c4f8fSDmytro Linkin 
1103885226f5SDmytro Linkin struct nsim_rate_node {
1104885226f5SDmytro Linkin 	struct dentry *ddir;
1105f3d101b4SDmytro Linkin 	struct dentry *rate_parent;
1106f3d101b4SDmytro Linkin 	char *parent_name;
1107885226f5SDmytro Linkin 	u16 tx_share;
1108885226f5SDmytro Linkin 	u16 tx_max;
1109885226f5SDmytro Linkin };
1110885226f5SDmytro Linkin 
1111885226f5SDmytro Linkin static int nsim_node_tx_share_set(struct devlink_rate *devlink_rate, void *priv,
1112885226f5SDmytro Linkin 				  u64 tx_share, struct netlink_ext_ack *extack)
1113885226f5SDmytro Linkin {
1114885226f5SDmytro Linkin 	struct nsim_rate_node *nsim_node = priv;
1115885226f5SDmytro Linkin 	int err;
1116885226f5SDmytro Linkin 
1117885226f5SDmytro Linkin 	err = nsim_rate_bytes_to_units("tx_share", &tx_share, extack);
1118885226f5SDmytro Linkin 	if (err)
1119885226f5SDmytro Linkin 		return err;
1120885226f5SDmytro Linkin 
1121885226f5SDmytro Linkin 	nsim_node->tx_share = tx_share;
1122885226f5SDmytro Linkin 	return 0;
1123885226f5SDmytro Linkin }
1124885226f5SDmytro Linkin 
1125885226f5SDmytro Linkin static int nsim_node_tx_max_set(struct devlink_rate *devlink_rate, void *priv,
1126885226f5SDmytro Linkin 				u64 tx_max, struct netlink_ext_ack *extack)
1127885226f5SDmytro Linkin {
1128885226f5SDmytro Linkin 	struct nsim_rate_node *nsim_node = priv;
1129885226f5SDmytro Linkin 	int err;
1130885226f5SDmytro Linkin 
1131885226f5SDmytro Linkin 	err = nsim_rate_bytes_to_units("tx_max", &tx_max, extack);
1132885226f5SDmytro Linkin 	if (err)
1133885226f5SDmytro Linkin 		return err;
1134885226f5SDmytro Linkin 
1135885226f5SDmytro Linkin 	nsim_node->tx_max = tx_max;
1136885226f5SDmytro Linkin 	return 0;
1137885226f5SDmytro Linkin }
1138885226f5SDmytro Linkin 
1139885226f5SDmytro Linkin static int nsim_rate_node_new(struct devlink_rate *node, void **priv,
1140885226f5SDmytro Linkin 			      struct netlink_ext_ack *extack)
1141885226f5SDmytro Linkin {
1142885226f5SDmytro Linkin 	struct nsim_dev *nsim_dev = devlink_priv(node->devlink);
1143885226f5SDmytro Linkin 	struct nsim_rate_node *nsim_node;
1144885226f5SDmytro Linkin 
1145885226f5SDmytro Linkin 	if (!nsim_esw_mode_is_switchdev(nsim_dev)) {
1146885226f5SDmytro Linkin 		NL_SET_ERR_MSG_MOD(extack, "Node creation allowed only in switchdev mode.");
1147885226f5SDmytro Linkin 		return -EOPNOTSUPP;
1148885226f5SDmytro Linkin 	}
1149885226f5SDmytro Linkin 
1150885226f5SDmytro Linkin 	nsim_node = kzalloc(sizeof(*nsim_node), GFP_KERNEL);
1151885226f5SDmytro Linkin 	if (!nsim_node)
1152885226f5SDmytro Linkin 		return -ENOMEM;
1153885226f5SDmytro Linkin 
1154885226f5SDmytro Linkin 	nsim_node->ddir = debugfs_create_dir(node->name, nsim_dev->nodes_ddir);
1155*4e744cb8SDan Carpenter 
1156885226f5SDmytro Linkin 	debugfs_create_u16("tx_share", 0400, nsim_node->ddir, &nsim_node->tx_share);
1157885226f5SDmytro Linkin 	debugfs_create_u16("tx_max", 0400, nsim_node->ddir, &nsim_node->tx_max);
1158f3d101b4SDmytro Linkin 	nsim_node->rate_parent = debugfs_create_file("rate_parent", 0400,
1159f3d101b4SDmytro Linkin 						     nsim_node->ddir,
1160f3d101b4SDmytro Linkin 						     &nsim_node->parent_name,
1161f3d101b4SDmytro Linkin 						     &nsim_dev_rate_parent_fops);
1162f3d101b4SDmytro Linkin 
1163885226f5SDmytro Linkin 	*priv = nsim_node;
1164885226f5SDmytro Linkin 	return 0;
1165885226f5SDmytro Linkin }
1166885226f5SDmytro Linkin 
1167885226f5SDmytro Linkin static int nsim_rate_node_del(struct devlink_rate *node, void *priv,
1168885226f5SDmytro Linkin 			      struct netlink_ext_ack *extack)
1169885226f5SDmytro Linkin {
1170885226f5SDmytro Linkin 	struct nsim_rate_node *nsim_node = priv;
1171885226f5SDmytro Linkin 
1172f3d101b4SDmytro Linkin 	debugfs_remove(nsim_node->rate_parent);
1173885226f5SDmytro Linkin 	debugfs_remove_recursive(nsim_node->ddir);
1174885226f5SDmytro Linkin 	kfree(nsim_node);
1175885226f5SDmytro Linkin 	return 0;
1176885226f5SDmytro Linkin }
1177885226f5SDmytro Linkin 
1178f3d101b4SDmytro Linkin static int nsim_rate_leaf_parent_set(struct devlink_rate *child,
1179f3d101b4SDmytro Linkin 				     struct devlink_rate *parent,
1180f3d101b4SDmytro Linkin 				     void *priv_child, void *priv_parent,
1181f3d101b4SDmytro Linkin 				     struct netlink_ext_ack *extack)
1182f3d101b4SDmytro Linkin {
1183f3d101b4SDmytro Linkin 	struct nsim_dev_port *nsim_dev_port = priv_child;
1184f3d101b4SDmytro Linkin 
1185f3d101b4SDmytro Linkin 	if (parent)
1186f3d101b4SDmytro Linkin 		nsim_dev_port->parent_name = parent->name;
1187f3d101b4SDmytro Linkin 	else
1188f3d101b4SDmytro Linkin 		nsim_dev_port->parent_name = NULL;
1189f3d101b4SDmytro Linkin 	return 0;
1190f3d101b4SDmytro Linkin }
1191f3d101b4SDmytro Linkin 
1192f3d101b4SDmytro Linkin static int nsim_rate_node_parent_set(struct devlink_rate *child,
1193f3d101b4SDmytro Linkin 				     struct devlink_rate *parent,
1194f3d101b4SDmytro Linkin 				     void *priv_child, void *priv_parent,
1195f3d101b4SDmytro Linkin 				     struct netlink_ext_ack *extack)
1196f3d101b4SDmytro Linkin {
1197f3d101b4SDmytro Linkin 	struct nsim_rate_node *nsim_node = priv_child;
1198f3d101b4SDmytro Linkin 
1199f3d101b4SDmytro Linkin 	if (parent)
1200f3d101b4SDmytro Linkin 		nsim_node->parent_name = parent->name;
1201f3d101b4SDmytro Linkin 	else
1202f3d101b4SDmytro Linkin 		nsim_node->parent_name = NULL;
1203f3d101b4SDmytro Linkin 	return 0;
1204f3d101b4SDmytro Linkin }
1205f3d101b4SDmytro Linkin 
12068fb4bc6fSJiri Pirko static const struct devlink_ops nsim_dev_devlink_ops = {
1207160dc373SDmytro Linkin 	.eswitch_mode_set = nsim_devlink_eswitch_mode_set,
1208160dc373SDmytro Linkin 	.eswitch_mode_get = nsim_devlink_eswitch_mode_get,
1209cbb58368SJacob Keller 	.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT |
1210cbb58368SJacob Keller 					 DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK,
1211ccdf0721SMoshe Shemesh 	.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
121297691069SJiri Pirko 	.reload_down = nsim_dev_reload_down,
121397691069SJiri Pirko 	.reload_up = nsim_dev_reload_up,
12148e23cc03SJiri Pirko 	.info_get = nsim_dev_info_get,
1215fa4dfc4aSJiri Pirko 	.flash_update = nsim_dev_flash_update,
1216da58f90fSIdo Schimmel 	.trap_init = nsim_dev_devlink_trap_init,
1217da58f90fSIdo Schimmel 	.trap_action_set = nsim_dev_devlink_trap_action_set,
12180dc8249aSIdo Schimmel 	.trap_group_set = nsim_dev_devlink_trap_group_set,
1219ad188458SIdo Schimmel 	.trap_policer_set = nsim_dev_devlink_trap_policer_set,
1220ad188458SIdo Schimmel 	.trap_policer_counter_get = nsim_dev_devlink_trap_policer_counter_get,
1221605c4f8fSDmytro Linkin 	.rate_leaf_tx_share_set = nsim_leaf_tx_share_set,
1222605c4f8fSDmytro Linkin 	.rate_leaf_tx_max_set = nsim_leaf_tx_max_set,
1223885226f5SDmytro Linkin 	.rate_node_tx_share_set = nsim_node_tx_share_set,
1224885226f5SDmytro Linkin 	.rate_node_tx_max_set = nsim_node_tx_max_set,
1225885226f5SDmytro Linkin 	.rate_node_new = nsim_rate_node_new,
1226885226f5SDmytro Linkin 	.rate_node_del = nsim_rate_node_del,
1227f3d101b4SDmytro Linkin 	.rate_leaf_parent_set = nsim_rate_leaf_parent_set,
1228f3d101b4SDmytro Linkin 	.rate_node_parent_set = nsim_rate_node_parent_set,
12298fb4bc6fSJiri Pirko };
12308fb4bc6fSJiri Pirko 
1231150e8f8aSJiri Pirko #define NSIM_DEV_MAX_MACS_DEFAULT 32
1232150e8f8aSJiri Pirko #define NSIM_DEV_TEST1_DEFAULT true
1233150e8f8aSJiri Pirko 
1234814b9ce6SDmytro Linkin static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type,
1235794b2c05SJiri Pirko 			       unsigned int port_index)
12368320d145SJiri Pirko {
123792ba1f29SDmytro Linkin 	struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev;
123871ad8d55SDanielle Ratson 	struct devlink_port_attrs attrs = {};
12398320d145SJiri Pirko 	struct nsim_dev_port *nsim_dev_port;
12408320d145SJiri Pirko 	struct devlink_port *devlink_port;
12418320d145SJiri Pirko 	int err;
12428320d145SJiri Pirko 
124392ba1f29SDmytro Linkin 	if (type == NSIM_DEV_PORT_TYPE_VF && !nsim_bus_dev->num_vfs)
124492ba1f29SDmytro Linkin 		return -EINVAL;
124592ba1f29SDmytro Linkin 
12468320d145SJiri Pirko 	nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL);
12478320d145SJiri Pirko 	if (!nsim_dev_port)
12488320d145SJiri Pirko 		return -ENOMEM;
1249814b9ce6SDmytro Linkin 	nsim_dev_port->port_index = nsim_dev_port_index(type, port_index);
1250814b9ce6SDmytro Linkin 	nsim_dev_port->port_type = type;
12518320d145SJiri Pirko 
12528320d145SJiri Pirko 	devlink_port = &nsim_dev_port->devlink_port;
125392ba1f29SDmytro Linkin 	if (nsim_dev_port_is_pf(nsim_dev_port)) {
125471ad8d55SDanielle Ratson 		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
125571ad8d55SDanielle Ratson 		attrs.phys.port_number = port_index + 1;
125692ba1f29SDmytro Linkin 	} else {
125792ba1f29SDmytro Linkin 		attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
125892ba1f29SDmytro Linkin 		attrs.pci_vf.pf = 0;
125992ba1f29SDmytro Linkin 		attrs.pci_vf.vf = port_index;
126092ba1f29SDmytro Linkin 	}
126171ad8d55SDanielle Ratson 	memcpy(attrs.switch_id.id, nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
126271ad8d55SDanielle Ratson 	attrs.switch_id.id_len = nsim_dev->switch_id.id_len;
126371ad8d55SDanielle Ratson 	devlink_port_attrs_set(devlink_port, &attrs);
12648320d145SJiri Pirko 	err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port,
1265814b9ce6SDmytro Linkin 				    nsim_dev_port->port_index);
12668320d145SJiri Pirko 	if (err)
12678320d145SJiri Pirko 		goto err_port_free;
12688320d145SJiri Pirko 
12698320d145SJiri Pirko 	err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port);
12708320d145SJiri Pirko 	if (err)
12718320d145SJiri Pirko 		goto err_dl_port_unregister;
12728320d145SJiri Pirko 
1273e05b2d14SJiri Pirko 	nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port);
1274e05b2d14SJiri Pirko 	if (IS_ERR(nsim_dev_port->ns)) {
1275e05b2d14SJiri Pirko 		err = PTR_ERR(nsim_dev_port->ns);
1276e05b2d14SJiri Pirko 		goto err_port_debugfs_exit;
1277e05b2d14SJiri Pirko 	}
1278e05b2d14SJiri Pirko 
1279885dfe12SDmytro Linkin 	if (nsim_dev_port_is_vf(nsim_dev_port)) {
1280885dfe12SDmytro Linkin 		err = devlink_rate_leaf_create(&nsim_dev_port->devlink_port,
1281885dfe12SDmytro Linkin 					       nsim_dev_port);
1282885dfe12SDmytro Linkin 		if (err)
1283885dfe12SDmytro Linkin 			goto err_nsim_destroy;
1284885dfe12SDmytro Linkin 	}
1285885dfe12SDmytro Linkin 
1286e05b2d14SJiri Pirko 	devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev);
12878320d145SJiri Pirko 	list_add(&nsim_dev_port->list, &nsim_dev->port_list);
12888320d145SJiri Pirko 
12898320d145SJiri Pirko 	return 0;
12908320d145SJiri Pirko 
1291885dfe12SDmytro Linkin err_nsim_destroy:
1292885dfe12SDmytro Linkin 	nsim_destroy(nsim_dev_port->ns);
1293e05b2d14SJiri Pirko err_port_debugfs_exit:
1294e05b2d14SJiri Pirko 	nsim_dev_port_debugfs_exit(nsim_dev_port);
12958320d145SJiri Pirko err_dl_port_unregister:
12968320d145SJiri Pirko 	devlink_port_unregister(devlink_port);
12978320d145SJiri Pirko err_port_free:
12988320d145SJiri Pirko 	kfree(nsim_dev_port);
12998320d145SJiri Pirko 	return err;
13008320d145SJiri Pirko }
13018320d145SJiri Pirko 
1302794b2c05SJiri Pirko static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
13038320d145SJiri Pirko {
13048320d145SJiri Pirko 	struct devlink_port *devlink_port = &nsim_dev_port->devlink_port;
13058320d145SJiri Pirko 
13068320d145SJiri Pirko 	list_del(&nsim_dev_port->list);
1307885dfe12SDmytro Linkin 	if (nsim_dev_port_is_vf(nsim_dev_port))
1308885dfe12SDmytro Linkin 		devlink_rate_leaf_destroy(&nsim_dev_port->devlink_port);
1309e05b2d14SJiri Pirko 	devlink_port_type_clear(devlink_port);
1310e05b2d14SJiri Pirko 	nsim_destroy(nsim_dev_port->ns);
13118320d145SJiri Pirko 	nsim_dev_port_debugfs_exit(nsim_dev_port);
13128320d145SJiri Pirko 	devlink_port_unregister(devlink_port);
13138320d145SJiri Pirko 	kfree(nsim_dev_port);
13148320d145SJiri Pirko }
13158320d145SJiri Pirko 
13168320d145SJiri Pirko static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev)
13178320d145SJiri Pirko {
13188320d145SJiri Pirko 	struct nsim_dev_port *nsim_dev_port, *tmp;
13198320d145SJiri Pirko 
13206d6f0383SIdo Schimmel 	mutex_lock(&nsim_dev->port_list_lock);
13218320d145SJiri Pirko 	list_for_each_entry_safe(nsim_dev_port, tmp,
13228320d145SJiri Pirko 				 &nsim_dev->port_list, list)
1323794b2c05SJiri Pirko 		__nsim_dev_port_del(nsim_dev_port);
13246d6f0383SIdo Schimmel 	mutex_unlock(&nsim_dev->port_list_lock);
13258320d145SJiri Pirko }
13268320d145SJiri Pirko 
13277f36a77aSJiri Pirko static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev,
13287f36a77aSJiri Pirko 				 unsigned int port_count)
13298320d145SJiri Pirko {
13307f36a77aSJiri Pirko 	int i, err;
13318320d145SJiri Pirko 
13327f36a77aSJiri Pirko 	for (i = 0; i < port_count; i++) {
1333814b9ce6SDmytro Linkin 		err = __nsim_dev_port_add(nsim_dev, NSIM_DEV_PORT_TYPE_PF, i);
13348320d145SJiri Pirko 		if (err)
13358320d145SJiri Pirko 			goto err_port_del_all;
13368320d145SJiri Pirko 	}
13378320d145SJiri Pirko 	return 0;
13388320d145SJiri Pirko 
13398320d145SJiri Pirko err_port_del_all:
13408320d145SJiri Pirko 	nsim_dev_port_del_all(nsim_dev);
13418320d145SJiri Pirko 	return err;
13428320d145SJiri Pirko }
13438320d145SJiri Pirko 
134475ba029fSJiri Pirko static int nsim_dev_reload_create(struct nsim_dev *nsim_dev,
134575ba029fSJiri Pirko 				  struct netlink_ext_ack *extack)
134675ba029fSJiri Pirko {
134775ba029fSJiri Pirko 	struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev;
134875ba029fSJiri Pirko 	struct devlink *devlink;
134975ba029fSJiri Pirko 	int err;
135075ba029fSJiri Pirko 
135175ba029fSJiri Pirko 	devlink = priv_to_devlink(nsim_dev);
135275ba029fSJiri Pirko 	nsim_dev = devlink_priv(devlink);
135375ba029fSJiri Pirko 	INIT_LIST_HEAD(&nsim_dev->port_list);
135475ba029fSJiri Pirko 	mutex_init(&nsim_dev->port_list_lock);
135575ba029fSJiri Pirko 	nsim_dev->fw_update_status = true;
1356cbb58368SJacob Keller 	nsim_dev->fw_update_overwrite_mask = 0;
135775ba029fSJiri Pirko 
135875ba029fSJiri Pirko 	nsim_devlink_param_load_driverinit_values(devlink);
135975ba029fSJiri Pirko 
136075ba029fSJiri Pirko 	err = nsim_dev_dummy_region_init(nsim_dev, devlink);
136175ba029fSJiri Pirko 	if (err)
1362f57ab5b7SIdo Schimmel 		return err;
136375ba029fSJiri Pirko 
136475ba029fSJiri Pirko 	err = nsim_dev_traps_init(devlink);
136575ba029fSJiri Pirko 	if (err)
136675ba029fSJiri Pirko 		goto err_dummy_region_exit;
136775ba029fSJiri Pirko 
1368f57ab5b7SIdo Schimmel 	nsim_dev->fib_data = nsim_fib_create(devlink, extack);
1369f57ab5b7SIdo Schimmel 	if (IS_ERR(nsim_dev->fib_data)) {
1370f57ab5b7SIdo Schimmel 		err = PTR_ERR(nsim_dev->fib_data);
1371f57ab5b7SIdo Schimmel 		goto err_traps_exit;
1372f57ab5b7SIdo Schimmel 	}
1373f57ab5b7SIdo Schimmel 
137482c93a87SJiri Pirko 	err = nsim_dev_health_init(nsim_dev, devlink);
137575ba029fSJiri Pirko 	if (err)
1376f57ab5b7SIdo Schimmel 		goto err_fib_destroy;
137775ba029fSJiri Pirko 
1378a8700c3dSIdo Schimmel 	err = nsim_dev_psample_init(nsim_dev);
137982c93a87SJiri Pirko 	if (err)
138082c93a87SJiri Pirko 		goto err_health_exit;
138182c93a87SJiri Pirko 
1382a8700c3dSIdo Schimmel 	err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count);
1383a8700c3dSIdo Schimmel 	if (err)
1384a8700c3dSIdo Schimmel 		goto err_psample_exit;
1385a8700c3dSIdo Schimmel 
13868526ad96STaehee Yoo 	nsim_dev->take_snapshot = debugfs_create_file("take_snapshot",
13878526ad96STaehee Yoo 						      0200,
13888526ad96STaehee Yoo 						      nsim_dev->ddir,
13898526ad96STaehee Yoo 						      nsim_dev,
13908526ad96STaehee Yoo 						&nsim_dev_take_snapshot_fops);
139175ba029fSJiri Pirko 	return 0;
139275ba029fSJiri Pirko 
1393a8700c3dSIdo Schimmel err_psample_exit:
1394a8700c3dSIdo Schimmel 	nsim_dev_psample_exit(nsim_dev);
139582c93a87SJiri Pirko err_health_exit:
139682c93a87SJiri Pirko 	nsim_dev_health_exit(nsim_dev);
1397f57ab5b7SIdo Schimmel err_fib_destroy:
1398f57ab5b7SIdo Schimmel 	nsim_fib_destroy(devlink, nsim_dev->fib_data);
139975ba029fSJiri Pirko err_traps_exit:
140075ba029fSJiri Pirko 	nsim_dev_traps_exit(devlink);
140175ba029fSJiri Pirko err_dummy_region_exit:
140275ba029fSJiri Pirko 	nsim_dev_dummy_region_exit(nsim_dev);
140375ba029fSJiri Pirko 	return err;
140475ba029fSJiri Pirko }
140575ba029fSJiri Pirko 
1406bfcccfe7SJakub Kicinski int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
14077f36a77aSJiri Pirko {
14087f36a77aSJiri Pirko 	struct nsim_dev *nsim_dev;
14097f36a77aSJiri Pirko 	struct devlink *devlink;
14107f36a77aSJiri Pirko 	int err;
14117f36a77aSJiri Pirko 
14127f36a77aSJiri Pirko 	devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev));
14137f36a77aSJiri Pirko 	if (!devlink)
1414bfcccfe7SJakub Kicinski 		return -ENOMEM;
14157b60027bSJiri Pirko 	devlink_net_set(devlink, nsim_bus_dev->initial_net);
14167f36a77aSJiri Pirko 	nsim_dev = devlink_priv(devlink);
14177f36a77aSJiri Pirko 	nsim_dev->nsim_bus_dev = nsim_bus_dev;
14187f36a77aSJiri Pirko 	nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id);
14197f36a77aSJiri Pirko 	get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
14207f36a77aSJiri Pirko 	INIT_LIST_HEAD(&nsim_dev->port_list);
14217f36a77aSJiri Pirko 	mutex_init(&nsim_dev->port_list_lock);
14227f36a77aSJiri Pirko 	nsim_dev->fw_update_status = true;
1423cbb58368SJacob Keller 	nsim_dev->fw_update_overwrite_mask = 0;
14247f36a77aSJiri Pirko 	nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT;
14257f36a77aSJiri Pirko 	nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT;
1426d3cbb907SJiri Pirko 	spin_lock_init(&nsim_dev->fa_cookie_lock);
14277f36a77aSJiri Pirko 
1428bfcccfe7SJakub Kicinski 	dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev);
1429bfcccfe7SJakub Kicinski 
14307f36a77aSJiri Pirko 	err = nsim_dev_resources_register(devlink);
14317f36a77aSJiri Pirko 	if (err)
14327f36a77aSJiri Pirko 		goto err_devlink_free;
14337f36a77aSJiri Pirko 
14347f36a77aSJiri Pirko 	err = devlink_register(devlink, &nsim_bus_dev->dev);
14357f36a77aSJiri Pirko 	if (err)
1436f57ab5b7SIdo Schimmel 		goto err_resources_unregister;
14377f36a77aSJiri Pirko 
14387f36a77aSJiri Pirko 	err = devlink_params_register(devlink, nsim_devlink_params,
14397f36a77aSJiri Pirko 				      ARRAY_SIZE(nsim_devlink_params));
14407f36a77aSJiri Pirko 	if (err)
14417f36a77aSJiri Pirko 		goto err_dl_unregister;
14427f36a77aSJiri Pirko 	nsim_devlink_set_params_init_values(nsim_dev, devlink);
14437f36a77aSJiri Pirko 
14447f36a77aSJiri Pirko 	err = nsim_dev_dummy_region_init(nsim_dev, devlink);
14457f36a77aSJiri Pirko 	if (err)
14467f36a77aSJiri Pirko 		goto err_params_unregister;
14477f36a77aSJiri Pirko 
14487f36a77aSJiri Pirko 	err = nsim_dev_traps_init(devlink);
14497f36a77aSJiri Pirko 	if (err)
14507f36a77aSJiri Pirko 		goto err_dummy_region_exit;
14517f36a77aSJiri Pirko 
14527f36a77aSJiri Pirko 	err = nsim_dev_debugfs_init(nsim_dev);
14537f36a77aSJiri Pirko 	if (err)
14547f36a77aSJiri Pirko 		goto err_traps_exit;
14557f36a77aSJiri Pirko 
1456f57ab5b7SIdo Schimmel 	nsim_dev->fib_data = nsim_fib_create(devlink, NULL);
1457f57ab5b7SIdo Schimmel 	if (IS_ERR(nsim_dev->fib_data)) {
1458f57ab5b7SIdo Schimmel 		err = PTR_ERR(nsim_dev->fib_data);
1459f57ab5b7SIdo Schimmel 		goto err_debugfs_exit;
1460f57ab5b7SIdo Schimmel 	}
1461f57ab5b7SIdo Schimmel 
146282c93a87SJiri Pirko 	err = nsim_dev_health_init(nsim_dev, devlink);
14637f36a77aSJiri Pirko 	if (err)
1464f57ab5b7SIdo Schimmel 		goto err_fib_destroy;
14657f36a77aSJiri Pirko 
146682c93a87SJiri Pirko 	err = nsim_bpf_dev_init(nsim_dev);
146782c93a87SJiri Pirko 	if (err)
146882c93a87SJiri Pirko 		goto err_health_exit;
146982c93a87SJiri Pirko 
1470a8700c3dSIdo Schimmel 	err = nsim_dev_psample_init(nsim_dev);
14717f36a77aSJiri Pirko 	if (err)
14727f36a77aSJiri Pirko 		goto err_bpf_dev_exit;
14737f36a77aSJiri Pirko 
1474a8700c3dSIdo Schimmel 	err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count);
1475a8700c3dSIdo Schimmel 	if (err)
1476a8700c3dSIdo Schimmel 		goto err_psample_exit;
1477a8700c3dSIdo Schimmel 
14787f36a77aSJiri Pirko 	devlink_params_publish(devlink);
1479a0c76345SJiri Pirko 	devlink_reload_enable(devlink);
1480160dc373SDmytro Linkin 	nsim_dev->esw_mode = DEVLINK_ESWITCH_MODE_LEGACY;
1481bfcccfe7SJakub Kicinski 	return 0;
14827f36a77aSJiri Pirko 
1483a8700c3dSIdo Schimmel err_psample_exit:
1484a8700c3dSIdo Schimmel 	nsim_dev_psample_exit(nsim_dev);
14857f36a77aSJiri Pirko err_bpf_dev_exit:
14867f36a77aSJiri Pirko 	nsim_bpf_dev_exit(nsim_dev);
148782c93a87SJiri Pirko err_health_exit:
148882c93a87SJiri Pirko 	nsim_dev_health_exit(nsim_dev);
1489f57ab5b7SIdo Schimmel err_fib_destroy:
1490f57ab5b7SIdo Schimmel 	nsim_fib_destroy(devlink, nsim_dev->fib_data);
14917f36a77aSJiri Pirko err_debugfs_exit:
14927f36a77aSJiri Pirko 	nsim_dev_debugfs_exit(nsim_dev);
14937f36a77aSJiri Pirko err_traps_exit:
14947f36a77aSJiri Pirko 	nsim_dev_traps_exit(devlink);
14957f36a77aSJiri Pirko err_dummy_region_exit:
14967f36a77aSJiri Pirko 	nsim_dev_dummy_region_exit(nsim_dev);
14977f36a77aSJiri Pirko err_params_unregister:
14987f36a77aSJiri Pirko 	devlink_params_unregister(devlink, nsim_devlink_params,
14997f36a77aSJiri Pirko 				  ARRAY_SIZE(nsim_devlink_params));
15007f36a77aSJiri Pirko err_dl_unregister:
15017f36a77aSJiri Pirko 	devlink_unregister(devlink);
15027f36a77aSJiri Pirko err_resources_unregister:
15037f36a77aSJiri Pirko 	devlink_resources_unregister(devlink, NULL);
15047f36a77aSJiri Pirko err_devlink_free:
15057f36a77aSJiri Pirko 	devlink_free(devlink);
1506bfcccfe7SJakub Kicinski 	return err;
15077f36a77aSJiri Pirko }
15087f36a77aSJiri Pirko 
150975ba029fSJiri Pirko static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev)
151075ba029fSJiri Pirko {
151175ba029fSJiri Pirko 	struct devlink *devlink = priv_to_devlink(nsim_dev);
151275ba029fSJiri Pirko 
151375ba029fSJiri Pirko 	if (devlink_is_reload_failed(devlink))
151475ba029fSJiri Pirko 		return;
15158526ad96STaehee Yoo 	debugfs_remove(nsim_dev->take_snapshot);
151632ac15d8SDmytro Linkin 
151732ac15d8SDmytro Linkin 	mutex_lock(&nsim_dev->nsim_bus_dev->vfs_lock);
151832ac15d8SDmytro Linkin 	if (nsim_dev->nsim_bus_dev->num_vfs)
151932ac15d8SDmytro Linkin 		nsim_bus_dev_vfs_disable(nsim_dev->nsim_bus_dev);
152032ac15d8SDmytro Linkin 	mutex_unlock(&nsim_dev->nsim_bus_dev->vfs_lock);
152132ac15d8SDmytro Linkin 
152275ba029fSJiri Pirko 	nsim_dev_port_del_all(nsim_dev);
1523a8700c3dSIdo Schimmel 	nsim_dev_psample_exit(nsim_dev);
152482c93a87SJiri Pirko 	nsim_dev_health_exit(nsim_dev);
1525f57ab5b7SIdo Schimmel 	nsim_fib_destroy(devlink, nsim_dev->fib_data);
152675ba029fSJiri Pirko 	nsim_dev_traps_exit(devlink);
152775ba029fSJiri Pirko 	nsim_dev_dummy_region_exit(nsim_dev);
152875ba029fSJiri Pirko 	mutex_destroy(&nsim_dev->port_list_lock);
152975ba029fSJiri Pirko }
153075ba029fSJiri Pirko 
1531bfcccfe7SJakub Kicinski void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)
15327f36a77aSJiri Pirko {
1533bfcccfe7SJakub Kicinski 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
15347f36a77aSJiri Pirko 	struct devlink *devlink = priv_to_devlink(nsim_dev);
15357f36a77aSJiri Pirko 
1536a0c76345SJiri Pirko 	devlink_reload_disable(devlink);
1537a0c76345SJiri Pirko 
153875ba029fSJiri Pirko 	nsim_dev_reload_destroy(nsim_dev);
153975ba029fSJiri Pirko 
15407f36a77aSJiri Pirko 	nsim_bpf_dev_exit(nsim_dev);
15417f36a77aSJiri Pirko 	nsim_dev_debugfs_exit(nsim_dev);
15427f36a77aSJiri Pirko 	devlink_params_unregister(devlink, nsim_devlink_params,
15437f36a77aSJiri Pirko 				  ARRAY_SIZE(nsim_devlink_params));
15447f36a77aSJiri Pirko 	devlink_unregister(devlink);
15457f36a77aSJiri Pirko 	devlink_resources_unregister(devlink, NULL);
15467f36a77aSJiri Pirko 	devlink_free(devlink);
15477f36a77aSJiri Pirko }
15487f36a77aSJiri Pirko 
1549794b2c05SJiri Pirko static struct nsim_dev_port *
1550814b9ce6SDmytro Linkin __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, enum nsim_dev_port_type type,
1551814b9ce6SDmytro Linkin 		       unsigned int port_index)
1552794b2c05SJiri Pirko {
1553794b2c05SJiri Pirko 	struct nsim_dev_port *nsim_dev_port;
1554794b2c05SJiri Pirko 
1555814b9ce6SDmytro Linkin 	port_index = nsim_dev_port_index(type, port_index);
1556794b2c05SJiri Pirko 	list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list)
1557794b2c05SJiri Pirko 		if (nsim_dev_port->port_index == port_index)
1558794b2c05SJiri Pirko 			return nsim_dev_port;
1559794b2c05SJiri Pirko 	return NULL;
1560794b2c05SJiri Pirko }
1561794b2c05SJiri Pirko 
1562814b9ce6SDmytro Linkin int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type,
1563794b2c05SJiri Pirko 		      unsigned int port_index)
1564794b2c05SJiri Pirko {
1565794b2c05SJiri Pirko 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
1566794b2c05SJiri Pirko 	int err;
1567794b2c05SJiri Pirko 
1568794b2c05SJiri Pirko 	mutex_lock(&nsim_dev->port_list_lock);
1569814b9ce6SDmytro Linkin 	if (__nsim_dev_port_lookup(nsim_dev, type, port_index))
1570794b2c05SJiri Pirko 		err = -EEXIST;
1571794b2c05SJiri Pirko 	else
1572814b9ce6SDmytro Linkin 		err = __nsim_dev_port_add(nsim_dev, type, port_index);
1573794b2c05SJiri Pirko 	mutex_unlock(&nsim_dev->port_list_lock);
1574794b2c05SJiri Pirko 	return err;
1575794b2c05SJiri Pirko }
1576794b2c05SJiri Pirko 
1577814b9ce6SDmytro Linkin int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, enum nsim_dev_port_type type,
1578794b2c05SJiri Pirko 		      unsigned int port_index)
1579794b2c05SJiri Pirko {
1580794b2c05SJiri Pirko 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
1581794b2c05SJiri Pirko 	struct nsim_dev_port *nsim_dev_port;
1582794b2c05SJiri Pirko 	int err = 0;
1583794b2c05SJiri Pirko 
1584794b2c05SJiri Pirko 	mutex_lock(&nsim_dev->port_list_lock);
1585814b9ce6SDmytro Linkin 	nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, type, port_index);
1586794b2c05SJiri Pirko 	if (!nsim_dev_port)
1587794b2c05SJiri Pirko 		err = -ENOENT;
1588794b2c05SJiri Pirko 	else
1589794b2c05SJiri Pirko 		__nsim_dev_port_del(nsim_dev_port);
1590794b2c05SJiri Pirko 	mutex_unlock(&nsim_dev->port_list_lock);
1591794b2c05SJiri Pirko 	return err;
1592794b2c05SJiri Pirko }
1593794b2c05SJiri Pirko 
1594d514f41eSJiri Pirko int nsim_dev_init(void)
1595d514f41eSJiri Pirko {
1596ab1d0cc0SJiri Pirko 	nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL);
159734611e69Skbuild test robot 	return PTR_ERR_OR_ZERO(nsim_dev_ddir);
1598d514f41eSJiri Pirko }
1599d514f41eSJiri Pirko 
1600d514f41eSJiri Pirko void nsim_dev_exit(void)
1601d514f41eSJiri Pirko {
1602d514f41eSJiri Pirko 	debugfs_remove_recursive(nsim_dev_ddir);
1603d514f41eSJiri Pirko }
1604