1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2019 Mellanox Technologies */
3 
4 #include <devlink.h>
5 
6 #include "mlx5_core.h"
7 #include "fw_reset.h"
8 #include "fs_core.h"
9 #include "eswitch.h"
10 #include "sf/dev/dev.h"
11 #include "sf/sf.h"
12 
13 static int mlx5_devlink_flash_update(struct devlink *devlink,
14 				     struct devlink_flash_update_params *params,
15 				     struct netlink_ext_ack *extack)
16 {
17 	struct mlx5_core_dev *dev = devlink_priv(devlink);
18 
19 	return mlx5_firmware_flash(dev, params->fw, extack);
20 }
21 
22 static u8 mlx5_fw_ver_major(u32 version)
23 {
24 	return (version >> 24) & 0xff;
25 }
26 
27 static u8 mlx5_fw_ver_minor(u32 version)
28 {
29 	return (version >> 16) & 0xff;
30 }
31 
32 static u16 mlx5_fw_ver_subminor(u32 version)
33 {
34 	return version & 0xffff;
35 }
36 
37 #define DEVLINK_FW_STRING_LEN 32
38 
39 static int
40 mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
41 		      struct netlink_ext_ack *extack)
42 {
43 	struct mlx5_core_dev *dev = devlink_priv(devlink);
44 	char version_str[DEVLINK_FW_STRING_LEN];
45 	u32 running_fw, stored_fw;
46 	int err;
47 
48 	err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
49 	if (err)
50 		return err;
51 
52 	err = devlink_info_version_fixed_put(req, "fw.psid", dev->board_id);
53 	if (err)
54 		return err;
55 
56 	err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
57 	if (err)
58 		return err;
59 
60 	snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
61 		 mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
62 		 mlx5_fw_ver_subminor(running_fw));
63 	err = devlink_info_version_running_put(req, "fw.version", version_str);
64 	if (err)
65 		return err;
66 
67 	/* no pending version, return running (stored) version */
68 	if (stored_fw == 0)
69 		stored_fw = running_fw;
70 
71 	snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
72 		 mlx5_fw_ver_major(stored_fw), mlx5_fw_ver_minor(stored_fw),
73 		 mlx5_fw_ver_subminor(stored_fw));
74 	err = devlink_info_version_stored_put(req, "fw.version", version_str);
75 	if (err)
76 		return err;
77 
78 	return 0;
79 }
80 
81 static int mlx5_devlink_reload_fw_activate(struct devlink *devlink, struct netlink_ext_ack *extack)
82 {
83 	struct mlx5_core_dev *dev = devlink_priv(devlink);
84 	u8 reset_level, reset_type, net_port_alive;
85 	int err;
86 
87 	err = mlx5_fw_reset_query(dev, &reset_level, &reset_type);
88 	if (err)
89 		return err;
90 	if (!(reset_level & MLX5_MFRL_REG_RESET_LEVEL3)) {
91 		NL_SET_ERR_MSG_MOD(extack, "FW activate requires reboot");
92 		return -EINVAL;
93 	}
94 
95 	net_port_alive = !!(reset_type & MLX5_MFRL_REG_RESET_TYPE_NET_PORT_ALIVE);
96 	err = mlx5_fw_reset_set_reset_sync(dev, net_port_alive);
97 	if (err)
98 		goto out;
99 
100 	err = mlx5_fw_reset_wait_reset_done(dev);
101 out:
102 	if (err)
103 		NL_SET_ERR_MSG_MOD(extack, "FW activate command failed");
104 	return err;
105 }
106 
107 static int mlx5_devlink_trigger_fw_live_patch(struct devlink *devlink,
108 					      struct netlink_ext_ack *extack)
109 {
110 	struct mlx5_core_dev *dev = devlink_priv(devlink);
111 	u8 reset_level;
112 	int err;
113 
114 	err = mlx5_fw_reset_query(dev, &reset_level, NULL);
115 	if (err)
116 		return err;
117 	if (!(reset_level & MLX5_MFRL_REG_RESET_LEVEL0)) {
118 		NL_SET_ERR_MSG_MOD(extack,
119 				   "FW upgrade to the stored FW can't be done by FW live patching");
120 		return -EINVAL;
121 	}
122 
123 	return mlx5_fw_reset_set_live_patch(dev);
124 }
125 
126 static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change,
127 				    enum devlink_reload_action action,
128 				    enum devlink_reload_limit limit,
129 				    struct netlink_ext_ack *extack)
130 {
131 	struct mlx5_core_dev *dev = devlink_priv(devlink);
132 	bool sf_dev_allocated;
133 
134 	sf_dev_allocated = mlx5_sf_dev_allocated(dev);
135 	if (sf_dev_allocated) {
136 		/* Reload results in deleting SF device which further results in
137 		 * unregistering devlink instance while holding devlink_mutext.
138 		 * Hence, do not support reload.
139 		 */
140 		NL_SET_ERR_MSG_MOD(extack, "reload is unsupported when SFs are allocated\n");
141 		return -EOPNOTSUPP;
142 	}
143 
144 	if (mlx5_lag_is_active(dev)) {
145 		NL_SET_ERR_MSG_MOD(extack, "reload is unsupported in Lag mode\n");
146 		return -EOPNOTSUPP;
147 	}
148 
149 	switch (action) {
150 	case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
151 		mlx5_unload_one(dev, false);
152 		return 0;
153 	case DEVLINK_RELOAD_ACTION_FW_ACTIVATE:
154 		if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET)
155 			return mlx5_devlink_trigger_fw_live_patch(devlink, extack);
156 		return mlx5_devlink_reload_fw_activate(devlink, extack);
157 	default:
158 		/* Unsupported action should not get to this function */
159 		WARN_ON(1);
160 		return -EOPNOTSUPP;
161 	}
162 }
163 
164 static int mlx5_devlink_reload_up(struct devlink *devlink, enum devlink_reload_action action,
165 				  enum devlink_reload_limit limit, u32 *actions_performed,
166 				  struct netlink_ext_ack *extack)
167 {
168 	struct mlx5_core_dev *dev = devlink_priv(devlink);
169 
170 	*actions_performed = BIT(action);
171 	switch (action) {
172 	case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
173 		return mlx5_load_one(dev, false);
174 	case DEVLINK_RELOAD_ACTION_FW_ACTIVATE:
175 		if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET)
176 			break;
177 		/* On fw_activate action, also driver is reloaded and reinit performed */
178 		*actions_performed |= BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT);
179 		return mlx5_load_one(dev, false);
180 	default:
181 		/* Unsupported action should not get to this function */
182 		WARN_ON(1);
183 		return -EOPNOTSUPP;
184 	}
185 
186 	return 0;
187 }
188 
189 static struct mlx5_devlink_trap *mlx5_find_trap_by_id(struct mlx5_core_dev *dev, int trap_id)
190 {
191 	struct mlx5_devlink_trap *dl_trap;
192 
193 	list_for_each_entry(dl_trap, &dev->priv.traps, list)
194 		if (dl_trap->trap.id == trap_id)
195 			return dl_trap;
196 
197 	return NULL;
198 }
199 
200 static int mlx5_devlink_trap_init(struct devlink *devlink, const struct devlink_trap *trap,
201 				  void *trap_ctx)
202 {
203 	struct mlx5_core_dev *dev = devlink_priv(devlink);
204 	struct mlx5_devlink_trap *dl_trap;
205 
206 	dl_trap = kzalloc(sizeof(*dl_trap), GFP_KERNEL);
207 	if (!dl_trap)
208 		return -ENOMEM;
209 
210 	dl_trap->trap.id = trap->id;
211 	dl_trap->trap.action = DEVLINK_TRAP_ACTION_DROP;
212 	dl_trap->item = trap_ctx;
213 
214 	if (mlx5_find_trap_by_id(dev, trap->id)) {
215 		kfree(dl_trap);
216 		mlx5_core_err(dev, "Devlink trap: Trap 0x%x already found", trap->id);
217 		return -EEXIST;
218 	}
219 
220 	list_add_tail(&dl_trap->list, &dev->priv.traps);
221 	return 0;
222 }
223 
224 static void mlx5_devlink_trap_fini(struct devlink *devlink, const struct devlink_trap *trap,
225 				   void *trap_ctx)
226 {
227 	struct mlx5_core_dev *dev = devlink_priv(devlink);
228 	struct mlx5_devlink_trap *dl_trap;
229 
230 	dl_trap = mlx5_find_trap_by_id(dev, trap->id);
231 	if (!dl_trap) {
232 		mlx5_core_err(dev, "Devlink trap: Missing trap id 0x%x", trap->id);
233 		return;
234 	}
235 	list_del(&dl_trap->list);
236 	kfree(dl_trap);
237 }
238 
239 static int mlx5_devlink_trap_action_set(struct devlink *devlink,
240 					const struct devlink_trap *trap,
241 					enum devlink_trap_action action,
242 					struct netlink_ext_ack *extack)
243 {
244 	struct mlx5_core_dev *dev = devlink_priv(devlink);
245 	enum devlink_trap_action action_orig;
246 	struct mlx5_devlink_trap *dl_trap;
247 	int err = 0;
248 
249 	dl_trap = mlx5_find_trap_by_id(dev, trap->id);
250 	if (!dl_trap) {
251 		mlx5_core_err(dev, "Devlink trap: Set action on invalid trap id 0x%x", trap->id);
252 		err = -EINVAL;
253 		goto out;
254 	}
255 
256 	if (action != DEVLINK_TRAP_ACTION_DROP && action != DEVLINK_TRAP_ACTION_TRAP) {
257 		err = -EOPNOTSUPP;
258 		goto out;
259 	}
260 
261 	if (action == dl_trap->trap.action)
262 		goto out;
263 
264 	action_orig = dl_trap->trap.action;
265 	dl_trap->trap.action = action;
266 	err = mlx5_blocking_notifier_call_chain(dev, MLX5_DRIVER_EVENT_TYPE_TRAP,
267 						&dl_trap->trap);
268 	if (err)
269 		dl_trap->trap.action = action_orig;
270 out:
271 	return err;
272 }
273 
274 static const struct devlink_ops mlx5_devlink_ops = {
275 #ifdef CONFIG_MLX5_ESWITCH
276 	.eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
277 	.eswitch_mode_get = mlx5_devlink_eswitch_mode_get,
278 	.eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set,
279 	.eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get,
280 	.eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set,
281 	.eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,
282 	.port_function_hw_addr_get = mlx5_devlink_port_function_hw_addr_get,
283 	.port_function_hw_addr_set = mlx5_devlink_port_function_hw_addr_set,
284 #endif
285 #ifdef CONFIG_MLX5_SF_MANAGER
286 	.port_new = mlx5_devlink_sf_port_new,
287 	.port_del = mlx5_devlink_sf_port_del,
288 	.port_fn_state_get = mlx5_devlink_sf_port_fn_state_get,
289 	.port_fn_state_set = mlx5_devlink_sf_port_fn_state_set,
290 #endif
291 	.flash_update = mlx5_devlink_flash_update,
292 	.info_get = mlx5_devlink_info_get,
293 	.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
294 			  BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE),
295 	.reload_limits = BIT(DEVLINK_RELOAD_LIMIT_NO_RESET),
296 	.reload_down = mlx5_devlink_reload_down,
297 	.reload_up = mlx5_devlink_reload_up,
298 	.trap_init = mlx5_devlink_trap_init,
299 	.trap_fini = mlx5_devlink_trap_fini,
300 	.trap_action_set = mlx5_devlink_trap_action_set,
301 };
302 
303 void mlx5_devlink_trap_report(struct mlx5_core_dev *dev, int trap_id, struct sk_buff *skb,
304 			      struct devlink_port *dl_port)
305 {
306 	struct devlink *devlink = priv_to_devlink(dev);
307 	struct mlx5_devlink_trap *dl_trap;
308 
309 	dl_trap = mlx5_find_trap_by_id(dev, trap_id);
310 	if (!dl_trap) {
311 		mlx5_core_err(dev, "Devlink trap: Report on invalid trap id 0x%x", trap_id);
312 		return;
313 	}
314 
315 	if (dl_trap->trap.action != DEVLINK_TRAP_ACTION_TRAP) {
316 		mlx5_core_dbg(dev, "Devlink trap: Trap id %d has action %d", trap_id,
317 			      dl_trap->trap.action);
318 		return;
319 	}
320 	devlink_trap_report(devlink, skb, dl_trap->item, dl_port, NULL);
321 }
322 
323 int mlx5_devlink_trap_get_num_active(struct mlx5_core_dev *dev)
324 {
325 	struct mlx5_devlink_trap *dl_trap;
326 	int count = 0;
327 
328 	list_for_each_entry(dl_trap, &dev->priv.traps, list)
329 		if (dl_trap->trap.action == DEVLINK_TRAP_ACTION_TRAP)
330 			count++;
331 
332 	return count;
333 }
334 
335 int mlx5_devlink_traps_get_action(struct mlx5_core_dev *dev, int trap_id,
336 				  enum devlink_trap_action *action)
337 {
338 	struct mlx5_devlink_trap *dl_trap;
339 
340 	dl_trap = mlx5_find_trap_by_id(dev, trap_id);
341 	if (!dl_trap) {
342 		mlx5_core_err(dev, "Devlink trap: Get action on invalid trap id 0x%x",
343 			      trap_id);
344 		return -EINVAL;
345 	}
346 
347 	*action = dl_trap->trap.action;
348 	return 0;
349 }
350 
351 struct devlink *mlx5_devlink_alloc(void)
352 {
353 	return devlink_alloc(&mlx5_devlink_ops, sizeof(struct mlx5_core_dev));
354 }
355 
356 void mlx5_devlink_free(struct devlink *devlink)
357 {
358 	devlink_free(devlink);
359 }
360 
361 static int mlx5_devlink_fs_mode_validate(struct devlink *devlink, u32 id,
362 					 union devlink_param_value val,
363 					 struct netlink_ext_ack *extack)
364 {
365 	struct mlx5_core_dev *dev = devlink_priv(devlink);
366 	char *value = val.vstr;
367 	int err = 0;
368 
369 	if (!strcmp(value, "dmfs")) {
370 		return 0;
371 	} else if (!strcmp(value, "smfs")) {
372 		u8 eswitch_mode;
373 		bool smfs_cap;
374 
375 		eswitch_mode = mlx5_eswitch_mode(dev);
376 		smfs_cap = mlx5_fs_dr_is_supported(dev);
377 
378 		if (!smfs_cap) {
379 			err = -EOPNOTSUPP;
380 			NL_SET_ERR_MSG_MOD(extack,
381 					   "Software managed steering is not supported by current device");
382 		}
383 
384 		else if (eswitch_mode == MLX5_ESWITCH_OFFLOADS) {
385 			NL_SET_ERR_MSG_MOD(extack,
386 					   "Software managed steering is not supported when eswitch offloads enabled.");
387 			err = -EOPNOTSUPP;
388 		}
389 	} else {
390 		NL_SET_ERR_MSG_MOD(extack,
391 				   "Bad parameter: supported values are [\"dmfs\", \"smfs\"]");
392 		err = -EINVAL;
393 	}
394 
395 	return err;
396 }
397 
398 static int mlx5_devlink_fs_mode_set(struct devlink *devlink, u32 id,
399 				    struct devlink_param_gset_ctx *ctx)
400 {
401 	struct mlx5_core_dev *dev = devlink_priv(devlink);
402 	enum mlx5_flow_steering_mode mode;
403 
404 	if (!strcmp(ctx->val.vstr, "smfs"))
405 		mode = MLX5_FLOW_STEERING_MODE_SMFS;
406 	else
407 		mode = MLX5_FLOW_STEERING_MODE_DMFS;
408 	dev->priv.steering->mode = mode;
409 
410 	return 0;
411 }
412 
413 static int mlx5_devlink_fs_mode_get(struct devlink *devlink, u32 id,
414 				    struct devlink_param_gset_ctx *ctx)
415 {
416 	struct mlx5_core_dev *dev = devlink_priv(devlink);
417 
418 	if (dev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_SMFS)
419 		strcpy(ctx->val.vstr, "smfs");
420 	else
421 		strcpy(ctx->val.vstr, "dmfs");
422 	return 0;
423 }
424 
425 static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id,
426 					     union devlink_param_value val,
427 					     struct netlink_ext_ack *extack)
428 {
429 	struct mlx5_core_dev *dev = devlink_priv(devlink);
430 	bool new_state = val.vbool;
431 
432 	if (new_state && !MLX5_CAP_GEN(dev, roce)) {
433 		NL_SET_ERR_MSG_MOD(extack, "Device doesn't support RoCE");
434 		return -EOPNOTSUPP;
435 	}
436 	if (mlx5_core_is_mp_slave(dev) || mlx5_lag_is_active(dev)) {
437 		NL_SET_ERR_MSG_MOD(extack, "Multi port slave/Lag device can't configure RoCE");
438 		return -EOPNOTSUPP;
439 	}
440 
441 	return 0;
442 }
443 
444 #ifdef CONFIG_MLX5_ESWITCH
445 static int mlx5_devlink_large_group_num_validate(struct devlink *devlink, u32 id,
446 						 union devlink_param_value val,
447 						 struct netlink_ext_ack *extack)
448 {
449 	int group_num = val.vu32;
450 
451 	if (group_num < 1 || group_num > 1024) {
452 		NL_SET_ERR_MSG_MOD(extack,
453 				   "Unsupported group number, supported range is 1-1024");
454 		return -EOPNOTSUPP;
455 	}
456 
457 	return 0;
458 }
459 #endif
460 
461 static int mlx5_devlink_enable_remote_dev_reset_set(struct devlink *devlink, u32 id,
462 						    struct devlink_param_gset_ctx *ctx)
463 {
464 	struct mlx5_core_dev *dev = devlink_priv(devlink);
465 
466 	mlx5_fw_reset_enable_remote_dev_reset_set(dev, ctx->val.vbool);
467 	return 0;
468 }
469 
470 static int mlx5_devlink_enable_remote_dev_reset_get(struct devlink *devlink, u32 id,
471 						    struct devlink_param_gset_ctx *ctx)
472 {
473 	struct mlx5_core_dev *dev = devlink_priv(devlink);
474 
475 	ctx->val.vbool = mlx5_fw_reset_enable_remote_dev_reset_get(dev);
476 	return 0;
477 }
478 
479 static const struct devlink_param mlx5_devlink_params[] = {
480 	DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_FLOW_STEERING_MODE,
481 			     "flow_steering_mode", DEVLINK_PARAM_TYPE_STRING,
482 			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
483 			     mlx5_devlink_fs_mode_get, mlx5_devlink_fs_mode_set,
484 			     mlx5_devlink_fs_mode_validate),
485 	DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
486 			      NULL, NULL, mlx5_devlink_enable_roce_validate),
487 #ifdef CONFIG_MLX5_ESWITCH
488 	DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM,
489 			     "fdb_large_groups", DEVLINK_PARAM_TYPE_U32,
490 			     BIT(DEVLINK_PARAM_CMODE_DRIVERINIT),
491 			     NULL, NULL,
492 			     mlx5_devlink_large_group_num_validate),
493 #endif
494 	DEVLINK_PARAM_GENERIC(ENABLE_REMOTE_DEV_RESET, BIT(DEVLINK_PARAM_CMODE_RUNTIME),
495 			      mlx5_devlink_enable_remote_dev_reset_get,
496 			      mlx5_devlink_enable_remote_dev_reset_set, NULL),
497 };
498 
499 static void mlx5_devlink_set_params_init_values(struct devlink *devlink)
500 {
501 	struct mlx5_core_dev *dev = devlink_priv(devlink);
502 	union devlink_param_value value;
503 
504 	if (dev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_DMFS)
505 		strcpy(value.vstr, "dmfs");
506 	else
507 		strcpy(value.vstr, "smfs");
508 	devlink_param_driverinit_value_set(devlink,
509 					   MLX5_DEVLINK_PARAM_ID_FLOW_STEERING_MODE,
510 					   value);
511 
512 	value.vbool = MLX5_CAP_GEN(dev, roce);
513 	devlink_param_driverinit_value_set(devlink,
514 					   DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
515 					   value);
516 
517 #ifdef CONFIG_MLX5_ESWITCH
518 	value.vu32 = ESW_OFFLOADS_DEFAULT_NUM_GROUPS;
519 	devlink_param_driverinit_value_set(devlink,
520 					   MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM,
521 					   value);
522 #endif
523 }
524 
525 #define MLX5_TRAP_DROP(_id, _group_id)					\
526 	DEVLINK_TRAP_GENERIC(DROP, DROP, _id,				\
527 			     DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \
528 			     DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT)
529 
530 static const struct devlink_trap mlx5_traps_arr[] = {
531 	MLX5_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS),
532 	MLX5_TRAP_DROP(DMAC_FILTER, L2_DROPS),
533 };
534 
535 static const struct devlink_trap_group mlx5_trap_groups_arr[] = {
536 	DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0),
537 };
538 
539 static int mlx5_devlink_traps_register(struct devlink *devlink)
540 {
541 	struct mlx5_core_dev *core_dev = devlink_priv(devlink);
542 	int err;
543 
544 	err = devlink_trap_groups_register(devlink, mlx5_trap_groups_arr,
545 					   ARRAY_SIZE(mlx5_trap_groups_arr));
546 	if (err)
547 		return err;
548 
549 	err = devlink_traps_register(devlink, mlx5_traps_arr, ARRAY_SIZE(mlx5_traps_arr),
550 				     &core_dev->priv);
551 	if (err)
552 		goto err_trap_group;
553 	return 0;
554 
555 err_trap_group:
556 	devlink_trap_groups_unregister(devlink, mlx5_trap_groups_arr,
557 				       ARRAY_SIZE(mlx5_trap_groups_arr));
558 	return err;
559 }
560 
561 static void mlx5_devlink_traps_unregister(struct devlink *devlink)
562 {
563 	devlink_traps_unregister(devlink, mlx5_traps_arr, ARRAY_SIZE(mlx5_traps_arr));
564 	devlink_trap_groups_unregister(devlink, mlx5_trap_groups_arr,
565 				       ARRAY_SIZE(mlx5_trap_groups_arr));
566 }
567 
568 int mlx5_devlink_register(struct devlink *devlink, struct device *dev)
569 {
570 	int err;
571 
572 	err = devlink_register(devlink, dev);
573 	if (err)
574 		return err;
575 
576 	err = devlink_params_register(devlink, mlx5_devlink_params,
577 				      ARRAY_SIZE(mlx5_devlink_params));
578 	if (err)
579 		goto params_reg_err;
580 	mlx5_devlink_set_params_init_values(devlink);
581 	devlink_params_publish(devlink);
582 
583 	err = mlx5_devlink_traps_register(devlink);
584 	if (err)
585 		goto traps_reg_err;
586 
587 	return 0;
588 
589 traps_reg_err:
590 	devlink_params_unregister(devlink, mlx5_devlink_params,
591 				  ARRAY_SIZE(mlx5_devlink_params));
592 params_reg_err:
593 	devlink_unregister(devlink);
594 	return err;
595 }
596 
597 void mlx5_devlink_unregister(struct devlink *devlink)
598 {
599 	mlx5_devlink_traps_unregister(devlink);
600 	devlink_params_unregister(devlink, mlx5_devlink_params,
601 				  ARRAY_SIZE(mlx5_devlink_params));
602 	devlink_unregister(devlink);
603 }
604