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 "esw/qos.h" |
11 | #include "sf/dev/dev.h" |
12 | #include "sf/sf.h" |
13 | |
14 | static int mlx5_devlink_flash_update(struct devlink *devlink, |
15 | struct devlink_flash_update_params *params, |
16 | struct netlink_ext_ack *extack) |
17 | { |
18 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
19 | |
20 | return mlx5_firmware_flash(dev, fw: params->fw, extack); |
21 | } |
22 | |
23 | static u8 mlx5_fw_ver_major(u32 version) |
24 | { |
25 | return (version >> 24) & 0xff; |
26 | } |
27 | |
28 | static u8 mlx5_fw_ver_minor(u32 version) |
29 | { |
30 | return (version >> 16) & 0xff; |
31 | } |
32 | |
33 | static u16 mlx5_fw_ver_subminor(u32 version) |
34 | { |
35 | return version & 0xffff; |
36 | } |
37 | |
38 | #define DEVLINK_FW_STRING_LEN 32 |
39 | |
40 | static int |
41 | mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, |
42 | struct netlink_ext_ack *extack) |
43 | { |
44 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
45 | char version_str[DEVLINK_FW_STRING_LEN]; |
46 | u32 running_fw, stored_fw; |
47 | int err; |
48 | |
49 | err = devlink_info_version_fixed_put(req, version_name: "fw.psid" , version_value: dev->board_id); |
50 | if (err) |
51 | return err; |
52 | |
53 | err = mlx5_fw_version_query(dev, running_ver: &running_fw, stored_ver: &stored_fw); |
54 | if (err) |
55 | return err; |
56 | |
57 | snprintf(buf: version_str, size: sizeof(version_str), fmt: "%d.%d.%04d" , |
58 | mlx5_fw_ver_major(version: running_fw), mlx5_fw_ver_minor(version: running_fw), |
59 | mlx5_fw_ver_subminor(version: running_fw)); |
60 | err = devlink_info_version_running_put(req, version_name: "fw.version" , version_value: version_str); |
61 | if (err) |
62 | return err; |
63 | err = devlink_info_version_running_put(req, |
64 | DEVLINK_INFO_VERSION_GENERIC_FW, |
65 | version_value: version_str); |
66 | if (err) |
67 | return err; |
68 | |
69 | /* no pending version, return running (stored) version */ |
70 | if (stored_fw == 0) |
71 | stored_fw = running_fw; |
72 | |
73 | snprintf(buf: version_str, size: sizeof(version_str), fmt: "%d.%d.%04d" , |
74 | mlx5_fw_ver_major(version: stored_fw), mlx5_fw_ver_minor(version: stored_fw), |
75 | mlx5_fw_ver_subminor(version: stored_fw)); |
76 | err = devlink_info_version_stored_put(req, version_name: "fw.version" , version_value: version_str); |
77 | if (err) |
78 | return err; |
79 | return devlink_info_version_stored_put(req, |
80 | DEVLINK_INFO_VERSION_GENERIC_FW, |
81 | version_value: version_str); |
82 | } |
83 | |
84 | static int mlx5_devlink_reload_fw_activate(struct devlink *devlink, struct netlink_ext_ack *extack) |
85 | { |
86 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
87 | u8 reset_level, reset_type, net_port_alive; |
88 | int err; |
89 | |
90 | err = mlx5_fw_reset_query(dev, reset_level: &reset_level, reset_type: &reset_type); |
91 | if (err) |
92 | return err; |
93 | if (!(reset_level & MLX5_MFRL_REG_RESET_LEVEL3)) { |
94 | NL_SET_ERR_MSG_MOD(extack, "FW activate requires reboot" ); |
95 | return -EINVAL; |
96 | } |
97 | |
98 | net_port_alive = !!(reset_type & MLX5_MFRL_REG_RESET_TYPE_NET_PORT_ALIVE); |
99 | err = mlx5_fw_reset_set_reset_sync(dev, reset_type_sel: net_port_alive, extack); |
100 | if (err) |
101 | return err; |
102 | |
103 | err = mlx5_fw_reset_wait_reset_done(dev); |
104 | if (err) |
105 | return err; |
106 | |
107 | mlx5_unload_one_devl_locked(dev, suspend: true); |
108 | err = mlx5_health_wait_pci_up(dev); |
109 | if (err) |
110 | NL_SET_ERR_MSG_MOD(extack, "FW activate aborted, PCI reads fail after reset" ); |
111 | |
112 | return err; |
113 | } |
114 | |
115 | static int mlx5_devlink_trigger_fw_live_patch(struct devlink *devlink, |
116 | struct netlink_ext_ack *extack) |
117 | { |
118 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
119 | u8 reset_level; |
120 | int err; |
121 | |
122 | err = mlx5_fw_reset_query(dev, reset_level: &reset_level, NULL); |
123 | if (err) |
124 | return err; |
125 | if (!(reset_level & MLX5_MFRL_REG_RESET_LEVEL0)) { |
126 | NL_SET_ERR_MSG_MOD(extack, |
127 | "FW upgrade to the stored FW can't be done by FW live patching" ); |
128 | return -EINVAL; |
129 | } |
130 | |
131 | return mlx5_fw_reset_set_live_patch(dev); |
132 | } |
133 | |
134 | static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, |
135 | enum devlink_reload_action action, |
136 | enum devlink_reload_limit limit, |
137 | struct netlink_ext_ack *extack) |
138 | { |
139 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
140 | struct pci_dev *pdev = dev->pdev; |
141 | int ret = 0; |
142 | |
143 | if (mlx5_dev_is_lightweight(dev)) { |
144 | if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) |
145 | return -EOPNOTSUPP; |
146 | mlx5_unload_one_light(dev); |
147 | return 0; |
148 | } |
149 | |
150 | if (mlx5_lag_is_active(dev)) { |
151 | NL_SET_ERR_MSG_MOD(extack, "reload is unsupported in Lag mode" ); |
152 | return -EOPNOTSUPP; |
153 | } |
154 | |
155 | if (mlx5_core_is_mp_slave(dev)) { |
156 | NL_SET_ERR_MSG_MOD(extack, "reload is unsupported for multi port slave" ); |
157 | return -EOPNOTSUPP; |
158 | } |
159 | |
160 | if (mlx5_core_is_pf(dev) && pci_num_vf(dev: pdev)) |
161 | NL_SET_ERR_MSG_MOD(extack, "reload while VFs are present is unfavorable" ); |
162 | |
163 | switch (action) { |
164 | case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: |
165 | mlx5_unload_one_devl_locked(dev, suspend: false); |
166 | break; |
167 | case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: |
168 | if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET) |
169 | ret = mlx5_devlink_trigger_fw_live_patch(devlink, extack); |
170 | else |
171 | ret = mlx5_devlink_reload_fw_activate(devlink, extack); |
172 | break; |
173 | default: |
174 | /* Unsupported action should not get to this function */ |
175 | WARN_ON(1); |
176 | ret = -EOPNOTSUPP; |
177 | } |
178 | |
179 | return ret; |
180 | } |
181 | |
182 | static int mlx5_devlink_reload_up(struct devlink *devlink, enum devlink_reload_action action, |
183 | enum devlink_reload_limit limit, u32 *actions_performed, |
184 | struct netlink_ext_ack *extack) |
185 | { |
186 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
187 | int ret = 0; |
188 | |
189 | *actions_performed = BIT(action); |
190 | switch (action) { |
191 | case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: |
192 | if (mlx5_dev_is_lightweight(dev)) { |
193 | mlx5_fw_reporters_create(dev); |
194 | return mlx5_init_one_devl_locked(dev); |
195 | } |
196 | ret = mlx5_load_one_devl_locked(dev, recovery: false); |
197 | break; |
198 | case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: |
199 | if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET) |
200 | break; |
201 | /* On fw_activate action, also driver is reloaded and reinit performed */ |
202 | *actions_performed |= BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); |
203 | ret = mlx5_load_one_devl_locked(dev, recovery: true); |
204 | if (ret) |
205 | return ret; |
206 | ret = mlx5_fw_reset_verify_fw_complete(dev, extack); |
207 | break; |
208 | default: |
209 | /* Unsupported action should not get to this function */ |
210 | WARN_ON(1); |
211 | ret = -EOPNOTSUPP; |
212 | } |
213 | |
214 | return ret; |
215 | } |
216 | |
217 | static struct mlx5_devlink_trap *mlx5_find_trap_by_id(struct mlx5_core_dev *dev, int trap_id) |
218 | { |
219 | struct mlx5_devlink_trap *dl_trap; |
220 | |
221 | list_for_each_entry(dl_trap, &dev->priv.traps, list) |
222 | if (dl_trap->trap.id == trap_id) |
223 | return dl_trap; |
224 | |
225 | return NULL; |
226 | } |
227 | |
228 | static int mlx5_devlink_trap_init(struct devlink *devlink, const struct devlink_trap *trap, |
229 | void *trap_ctx) |
230 | { |
231 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
232 | struct mlx5_devlink_trap *dl_trap; |
233 | |
234 | dl_trap = kzalloc(size: sizeof(*dl_trap), GFP_KERNEL); |
235 | if (!dl_trap) |
236 | return -ENOMEM; |
237 | |
238 | dl_trap->trap.id = trap->id; |
239 | dl_trap->trap.action = DEVLINK_TRAP_ACTION_DROP; |
240 | dl_trap->item = trap_ctx; |
241 | |
242 | if (mlx5_find_trap_by_id(dev, trap_id: trap->id)) { |
243 | kfree(objp: dl_trap); |
244 | mlx5_core_err(dev, "Devlink trap: Trap 0x%x already found" , trap->id); |
245 | return -EEXIST; |
246 | } |
247 | |
248 | list_add_tail(new: &dl_trap->list, head: &dev->priv.traps); |
249 | return 0; |
250 | } |
251 | |
252 | static void mlx5_devlink_trap_fini(struct devlink *devlink, const struct devlink_trap *trap, |
253 | void *trap_ctx) |
254 | { |
255 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
256 | struct mlx5_devlink_trap *dl_trap; |
257 | |
258 | dl_trap = mlx5_find_trap_by_id(dev, trap_id: trap->id); |
259 | if (!dl_trap) { |
260 | mlx5_core_err(dev, "Devlink trap: Missing trap id 0x%x" , trap->id); |
261 | return; |
262 | } |
263 | list_del(entry: &dl_trap->list); |
264 | kfree(objp: dl_trap); |
265 | } |
266 | |
267 | static int mlx5_devlink_trap_action_set(struct devlink *devlink, |
268 | const struct devlink_trap *trap, |
269 | enum devlink_trap_action action, |
270 | struct netlink_ext_ack *extack) |
271 | { |
272 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
273 | struct mlx5_devlink_trap_event_ctx trap_event_ctx; |
274 | enum devlink_trap_action action_orig; |
275 | struct mlx5_devlink_trap *dl_trap; |
276 | int err; |
277 | |
278 | if (is_mdev_switchdev_mode(dev)) { |
279 | NL_SET_ERR_MSG_MOD(extack, "Devlink traps can't be set in switchdev mode" ); |
280 | return -EOPNOTSUPP; |
281 | } |
282 | |
283 | dl_trap = mlx5_find_trap_by_id(dev, trap_id: trap->id); |
284 | if (!dl_trap) { |
285 | mlx5_core_err(dev, "Devlink trap: Set action on invalid trap id 0x%x" , trap->id); |
286 | return -EINVAL; |
287 | } |
288 | |
289 | if (action != DEVLINK_TRAP_ACTION_DROP && action != DEVLINK_TRAP_ACTION_TRAP) |
290 | return -EOPNOTSUPP; |
291 | |
292 | if (action == dl_trap->trap.action) |
293 | return 0; |
294 | |
295 | action_orig = dl_trap->trap.action; |
296 | dl_trap->trap.action = action; |
297 | trap_event_ctx.trap = &dl_trap->trap; |
298 | trap_event_ctx.err = 0; |
299 | err = mlx5_blocking_notifier_call_chain(dev, event: MLX5_DRIVER_EVENT_TYPE_TRAP, |
300 | data: &trap_event_ctx); |
301 | if (err == NOTIFY_BAD) |
302 | dl_trap->trap.action = action_orig; |
303 | |
304 | return trap_event_ctx.err; |
305 | } |
306 | |
307 | static const struct devlink_ops mlx5_devlink_ops = { |
308 | #ifdef CONFIG_MLX5_ESWITCH |
309 | .eswitch_mode_set = mlx5_devlink_eswitch_mode_set, |
310 | .eswitch_mode_get = mlx5_devlink_eswitch_mode_get, |
311 | .eswitch_inline_mode_set = mlx5_devlink_eswitch_inline_mode_set, |
312 | .eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get, |
313 | .eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set, |
314 | .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get, |
315 | .rate_leaf_tx_share_set = mlx5_esw_devlink_rate_leaf_tx_share_set, |
316 | .rate_leaf_tx_max_set = mlx5_esw_devlink_rate_leaf_tx_max_set, |
317 | .rate_node_tx_share_set = mlx5_esw_devlink_rate_node_tx_share_set, |
318 | .rate_node_tx_max_set = mlx5_esw_devlink_rate_node_tx_max_set, |
319 | .rate_node_new = mlx5_esw_devlink_rate_node_new, |
320 | .rate_node_del = mlx5_esw_devlink_rate_node_del, |
321 | .rate_leaf_parent_set = mlx5_esw_devlink_rate_parent_set, |
322 | #endif |
323 | #ifdef CONFIG_MLX5_SF_MANAGER |
324 | .port_new = mlx5_devlink_sf_port_new, |
325 | #endif |
326 | .flash_update = mlx5_devlink_flash_update, |
327 | .info_get = mlx5_devlink_info_get, |
328 | .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | |
329 | BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), |
330 | .reload_limits = BIT(DEVLINK_RELOAD_LIMIT_NO_RESET), |
331 | .reload_down = mlx5_devlink_reload_down, |
332 | .reload_up = mlx5_devlink_reload_up, |
333 | .trap_init = mlx5_devlink_trap_init, |
334 | .trap_fini = mlx5_devlink_trap_fini, |
335 | .trap_action_set = mlx5_devlink_trap_action_set, |
336 | }; |
337 | |
338 | void mlx5_devlink_trap_report(struct mlx5_core_dev *dev, int trap_id, struct sk_buff *skb, |
339 | struct devlink_port *dl_port) |
340 | { |
341 | struct devlink *devlink = priv_to_devlink(priv: dev); |
342 | struct mlx5_devlink_trap *dl_trap; |
343 | |
344 | dl_trap = mlx5_find_trap_by_id(dev, trap_id); |
345 | if (!dl_trap) { |
346 | mlx5_core_err(dev, "Devlink trap: Report on invalid trap id 0x%x" , trap_id); |
347 | return; |
348 | } |
349 | |
350 | if (dl_trap->trap.action != DEVLINK_TRAP_ACTION_TRAP) { |
351 | mlx5_core_dbg(dev, "Devlink trap: Trap id %d has action %d" , trap_id, |
352 | dl_trap->trap.action); |
353 | return; |
354 | } |
355 | devlink_trap_report(devlink, skb, trap_ctx: dl_trap->item, in_devlink_port: dl_port, NULL); |
356 | } |
357 | |
358 | int mlx5_devlink_trap_get_num_active(struct mlx5_core_dev *dev) |
359 | { |
360 | struct mlx5_devlink_trap *dl_trap; |
361 | int count = 0; |
362 | |
363 | list_for_each_entry(dl_trap, &dev->priv.traps, list) |
364 | if (dl_trap->trap.action == DEVLINK_TRAP_ACTION_TRAP) |
365 | count++; |
366 | |
367 | return count; |
368 | } |
369 | |
370 | int mlx5_devlink_traps_get_action(struct mlx5_core_dev *dev, int trap_id, |
371 | enum devlink_trap_action *action) |
372 | { |
373 | struct mlx5_devlink_trap *dl_trap; |
374 | |
375 | dl_trap = mlx5_find_trap_by_id(dev, trap_id); |
376 | if (!dl_trap) { |
377 | mlx5_core_err(dev, "Devlink trap: Get action on invalid trap id 0x%x" , |
378 | trap_id); |
379 | return -EINVAL; |
380 | } |
381 | |
382 | *action = dl_trap->trap.action; |
383 | return 0; |
384 | } |
385 | |
386 | struct devlink *mlx5_devlink_alloc(struct device *dev) |
387 | { |
388 | return devlink_alloc(ops: &mlx5_devlink_ops, priv_size: sizeof(struct mlx5_core_dev), |
389 | dev); |
390 | } |
391 | |
392 | void mlx5_devlink_free(struct devlink *devlink) |
393 | { |
394 | devlink_free(devlink); |
395 | } |
396 | |
397 | static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id, |
398 | union devlink_param_value val, |
399 | struct netlink_ext_ack *extack) |
400 | { |
401 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
402 | bool new_state = val.vbool; |
403 | |
404 | if (new_state && !MLX5_CAP_GEN(dev, roce) && |
405 | !(MLX5_CAP_GEN(dev, roce_rw_supported) && MLX5_CAP_GEN_MAX(dev, roce))) { |
406 | NL_SET_ERR_MSG_MOD(extack, "Device doesn't support RoCE" ); |
407 | return -EOPNOTSUPP; |
408 | } |
409 | if (mlx5_core_is_mp_slave(dev) || mlx5_lag_is_active(dev)) { |
410 | NL_SET_ERR_MSG_MOD(extack, "Multi port slave/Lag device can't configure RoCE" ); |
411 | return -EOPNOTSUPP; |
412 | } |
413 | |
414 | return 0; |
415 | } |
416 | |
417 | #ifdef CONFIG_MLX5_ESWITCH |
418 | static int mlx5_devlink_large_group_num_validate(struct devlink *devlink, u32 id, |
419 | union devlink_param_value val, |
420 | struct netlink_ext_ack *extack) |
421 | { |
422 | int group_num = val.vu32; |
423 | |
424 | if (group_num < 1 || group_num > 1024) { |
425 | NL_SET_ERR_MSG_MOD(extack, |
426 | "Unsupported group number, supported range is 1-1024" ); |
427 | return -EOPNOTSUPP; |
428 | } |
429 | |
430 | return 0; |
431 | } |
432 | #endif |
433 | |
434 | static int mlx5_devlink_eq_depth_validate(struct devlink *devlink, u32 id, |
435 | union devlink_param_value val, |
436 | struct netlink_ext_ack *extack) |
437 | { |
438 | return (val.vu32 >= 64 && val.vu32 <= 4096) ? 0 : -EINVAL; |
439 | } |
440 | |
441 | static int |
442 | mlx5_devlink_hairpin_num_queues_validate(struct devlink *devlink, u32 id, |
443 | union devlink_param_value val, |
444 | struct netlink_ext_ack *extack) |
445 | { |
446 | return val.vu32 ? 0 : -EINVAL; |
447 | } |
448 | |
449 | static int |
450 | mlx5_devlink_hairpin_queue_size_validate(struct devlink *devlink, u32 id, |
451 | union devlink_param_value val, |
452 | struct netlink_ext_ack *extack) |
453 | { |
454 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
455 | u32 val32 = val.vu32; |
456 | |
457 | if (!is_power_of_2(n: val32)) { |
458 | NL_SET_ERR_MSG_MOD(extack, "Value is not power of two" ); |
459 | return -EINVAL; |
460 | } |
461 | |
462 | if (val32 > BIT(MLX5_CAP_GEN(dev, log_max_hairpin_num_packets))) { |
463 | NL_SET_ERR_MSG_FMT_MOD( |
464 | extack, "Maximum hairpin queue size is %lu" , |
465 | BIT(MLX5_CAP_GEN(dev, log_max_hairpin_num_packets))); |
466 | return -EINVAL; |
467 | } |
468 | |
469 | return 0; |
470 | } |
471 | |
472 | static void mlx5_devlink_hairpin_params_init_values(struct devlink *devlink) |
473 | { |
474 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
475 | union devlink_param_value value; |
476 | u32 link_speed = 0; |
477 | u64 link_speed64; |
478 | |
479 | /* set hairpin pair per each 50Gbs share of the link */ |
480 | mlx5_port_max_linkspeed(mdev: dev, speed: &link_speed); |
481 | link_speed = max_t(u32, link_speed, 50000); |
482 | link_speed64 = link_speed; |
483 | do_div(link_speed64, 50000); |
484 | |
485 | value.vu32 = link_speed64; |
486 | devl_param_driverinit_value_set( |
487 | devlink, param_id: MLX5_DEVLINK_PARAM_ID_HAIRPIN_NUM_QUEUES, init_val: value); |
488 | |
489 | value.vu32 = |
490 | BIT(min_t(u32, 16 - MLX5_MPWRQ_MIN_LOG_STRIDE_SZ(dev), |
491 | MLX5_CAP_GEN(dev, log_max_hairpin_num_packets))); |
492 | devl_param_driverinit_value_set( |
493 | devlink, param_id: MLX5_DEVLINK_PARAM_ID_HAIRPIN_QUEUE_SIZE, init_val: value); |
494 | } |
495 | |
496 | static const struct devlink_param mlx5_devlink_params[] = { |
497 | DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
498 | NULL, NULL, mlx5_devlink_enable_roce_validate), |
499 | #ifdef CONFIG_MLX5_ESWITCH |
500 | DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM, |
501 | "fdb_large_groups" , DEVLINK_PARAM_TYPE_U32, |
502 | BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
503 | NULL, NULL, |
504 | mlx5_devlink_large_group_num_validate), |
505 | #endif |
506 | DEVLINK_PARAM_GENERIC(IO_EQ_SIZE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
507 | NULL, NULL, mlx5_devlink_eq_depth_validate), |
508 | DEVLINK_PARAM_GENERIC(EVENT_EQ_SIZE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
509 | NULL, NULL, mlx5_devlink_eq_depth_validate), |
510 | }; |
511 | |
512 | static void mlx5_devlink_set_params_init_values(struct devlink *devlink) |
513 | { |
514 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
515 | union devlink_param_value value; |
516 | |
517 | value.vbool = MLX5_CAP_GEN(dev, roce) && !mlx5_dev_is_lightweight(dev); |
518 | devl_param_driverinit_value_set(devlink, |
519 | param_id: DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, |
520 | init_val: value); |
521 | |
522 | #ifdef CONFIG_MLX5_ESWITCH |
523 | value.vu32 = ESW_OFFLOADS_DEFAULT_NUM_GROUPS; |
524 | devl_param_driverinit_value_set(devlink, |
525 | param_id: MLX5_DEVLINK_PARAM_ID_ESW_LARGE_GROUP_NUM, |
526 | init_val: value); |
527 | #endif |
528 | |
529 | value.vu32 = MLX5_COMP_EQ_SIZE; |
530 | devl_param_driverinit_value_set(devlink, |
531 | param_id: DEVLINK_PARAM_GENERIC_ID_IO_EQ_SIZE, |
532 | init_val: value); |
533 | |
534 | value.vu32 = MLX5_NUM_ASYNC_EQE; |
535 | devl_param_driverinit_value_set(devlink, |
536 | param_id: DEVLINK_PARAM_GENERIC_ID_EVENT_EQ_SIZE, |
537 | init_val: value); |
538 | } |
539 | |
540 | static const struct devlink_param mlx5_devlink_eth_params[] = { |
541 | DEVLINK_PARAM_GENERIC(ENABLE_ETH, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
542 | NULL, NULL, NULL), |
543 | DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_HAIRPIN_NUM_QUEUES, |
544 | "hairpin_num_queues" , DEVLINK_PARAM_TYPE_U32, |
545 | BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL, |
546 | mlx5_devlink_hairpin_num_queues_validate), |
547 | DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_HAIRPIN_QUEUE_SIZE, |
548 | "hairpin_queue_size" , DEVLINK_PARAM_TYPE_U32, |
549 | BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL, |
550 | mlx5_devlink_hairpin_queue_size_validate), |
551 | }; |
552 | |
553 | static int mlx5_devlink_eth_params_register(struct devlink *devlink) |
554 | { |
555 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
556 | union devlink_param_value value; |
557 | int err; |
558 | |
559 | if (!mlx5_eth_supported(dev)) |
560 | return 0; |
561 | |
562 | err = devl_params_register(devlink, params: mlx5_devlink_eth_params, |
563 | ARRAY_SIZE(mlx5_devlink_eth_params)); |
564 | if (err) |
565 | return err; |
566 | |
567 | value.vbool = !mlx5_dev_is_lightweight(dev); |
568 | devl_param_driverinit_value_set(devlink, |
569 | param_id: DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH, |
570 | init_val: value); |
571 | |
572 | mlx5_devlink_hairpin_params_init_values(devlink); |
573 | |
574 | return 0; |
575 | } |
576 | |
577 | static void mlx5_devlink_eth_params_unregister(struct devlink *devlink) |
578 | { |
579 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
580 | |
581 | if (!mlx5_eth_supported(dev)) |
582 | return; |
583 | |
584 | devl_params_unregister(devlink, params: mlx5_devlink_eth_params, |
585 | ARRAY_SIZE(mlx5_devlink_eth_params)); |
586 | } |
587 | |
588 | static int mlx5_devlink_enable_rdma_validate(struct devlink *devlink, u32 id, |
589 | union devlink_param_value val, |
590 | struct netlink_ext_ack *extack) |
591 | { |
592 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
593 | bool new_state = val.vbool; |
594 | |
595 | if (new_state && !mlx5_rdma_supported(dev)) |
596 | return -EOPNOTSUPP; |
597 | return 0; |
598 | } |
599 | |
600 | static const struct devlink_param mlx5_devlink_rdma_params[] = { |
601 | DEVLINK_PARAM_GENERIC(ENABLE_RDMA, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
602 | NULL, NULL, mlx5_devlink_enable_rdma_validate), |
603 | }; |
604 | |
605 | static int mlx5_devlink_rdma_params_register(struct devlink *devlink) |
606 | { |
607 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
608 | union devlink_param_value value; |
609 | int err; |
610 | |
611 | if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND)) |
612 | return 0; |
613 | |
614 | err = devl_params_register(devlink, params: mlx5_devlink_rdma_params, |
615 | ARRAY_SIZE(mlx5_devlink_rdma_params)); |
616 | if (err) |
617 | return err; |
618 | |
619 | value.vbool = !mlx5_dev_is_lightweight(dev); |
620 | devl_param_driverinit_value_set(devlink, |
621 | param_id: DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA, |
622 | init_val: value); |
623 | return 0; |
624 | } |
625 | |
626 | static void mlx5_devlink_rdma_params_unregister(struct devlink *devlink) |
627 | { |
628 | if (!IS_ENABLED(CONFIG_MLX5_INFINIBAND)) |
629 | return; |
630 | |
631 | devl_params_unregister(devlink, params: mlx5_devlink_rdma_params, |
632 | ARRAY_SIZE(mlx5_devlink_rdma_params)); |
633 | } |
634 | |
635 | static const struct devlink_param mlx5_devlink_vnet_params[] = { |
636 | DEVLINK_PARAM_GENERIC(ENABLE_VNET, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
637 | NULL, NULL, NULL), |
638 | }; |
639 | |
640 | static int mlx5_devlink_vnet_params_register(struct devlink *devlink) |
641 | { |
642 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
643 | union devlink_param_value value; |
644 | int err; |
645 | |
646 | if (!mlx5_vnet_supported(dev)) |
647 | return 0; |
648 | |
649 | err = devl_params_register(devlink, params: mlx5_devlink_vnet_params, |
650 | ARRAY_SIZE(mlx5_devlink_vnet_params)); |
651 | if (err) |
652 | return err; |
653 | |
654 | value.vbool = !mlx5_dev_is_lightweight(dev); |
655 | devl_param_driverinit_value_set(devlink, |
656 | param_id: DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET, |
657 | init_val: value); |
658 | return 0; |
659 | } |
660 | |
661 | static void mlx5_devlink_vnet_params_unregister(struct devlink *devlink) |
662 | { |
663 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
664 | |
665 | if (!mlx5_vnet_supported(dev)) |
666 | return; |
667 | |
668 | devl_params_unregister(devlink, params: mlx5_devlink_vnet_params, |
669 | ARRAY_SIZE(mlx5_devlink_vnet_params)); |
670 | } |
671 | |
672 | static int mlx5_devlink_auxdev_params_register(struct devlink *devlink) |
673 | { |
674 | int err; |
675 | |
676 | err = mlx5_devlink_eth_params_register(devlink); |
677 | if (err) |
678 | return err; |
679 | |
680 | err = mlx5_devlink_rdma_params_register(devlink); |
681 | if (err) |
682 | goto rdma_err; |
683 | |
684 | err = mlx5_devlink_vnet_params_register(devlink); |
685 | if (err) |
686 | goto vnet_err; |
687 | return 0; |
688 | |
689 | vnet_err: |
690 | mlx5_devlink_rdma_params_unregister(devlink); |
691 | rdma_err: |
692 | mlx5_devlink_eth_params_unregister(devlink); |
693 | return err; |
694 | } |
695 | |
696 | static void mlx5_devlink_auxdev_params_unregister(struct devlink *devlink) |
697 | { |
698 | mlx5_devlink_vnet_params_unregister(devlink); |
699 | mlx5_devlink_rdma_params_unregister(devlink); |
700 | mlx5_devlink_eth_params_unregister(devlink); |
701 | } |
702 | |
703 | static int mlx5_devlink_max_uc_list_validate(struct devlink *devlink, u32 id, |
704 | union devlink_param_value val, |
705 | struct netlink_ext_ack *extack) |
706 | { |
707 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
708 | |
709 | if (val.vu32 == 0) { |
710 | NL_SET_ERR_MSG_MOD(extack, "max_macs value must be greater than 0" ); |
711 | return -EINVAL; |
712 | } |
713 | |
714 | if (!is_power_of_2(n: val.vu32)) { |
715 | NL_SET_ERR_MSG_MOD(extack, "Only power of 2 values are supported for max_macs" ); |
716 | return -EINVAL; |
717 | } |
718 | |
719 | if (ilog2(val.vu32) > |
720 | MLX5_CAP_GEN_MAX(dev, log_max_current_uc_list)) { |
721 | NL_SET_ERR_MSG_MOD(extack, "max_macs value is out of the supported range" ); |
722 | return -EINVAL; |
723 | } |
724 | |
725 | return 0; |
726 | } |
727 | |
728 | static const struct devlink_param mlx5_devlink_max_uc_list_params[] = { |
729 | DEVLINK_PARAM_GENERIC(MAX_MACS, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), |
730 | NULL, NULL, mlx5_devlink_max_uc_list_validate), |
731 | }; |
732 | |
733 | static int mlx5_devlink_max_uc_list_params_register(struct devlink *devlink) |
734 | { |
735 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
736 | union devlink_param_value value; |
737 | int err; |
738 | |
739 | if (!MLX5_CAP_GEN_MAX(dev, log_max_current_uc_list_wr_supported)) |
740 | return 0; |
741 | |
742 | err = devl_params_register(devlink, params: mlx5_devlink_max_uc_list_params, |
743 | ARRAY_SIZE(mlx5_devlink_max_uc_list_params)); |
744 | if (err) |
745 | return err; |
746 | |
747 | value.vu32 = 1 << MLX5_CAP_GEN(dev, log_max_current_uc_list); |
748 | devl_param_driverinit_value_set(devlink, |
749 | param_id: DEVLINK_PARAM_GENERIC_ID_MAX_MACS, |
750 | init_val: value); |
751 | return 0; |
752 | } |
753 | |
754 | static void |
755 | mlx5_devlink_max_uc_list_params_unregister(struct devlink *devlink) |
756 | { |
757 | struct mlx5_core_dev *dev = devlink_priv(devlink); |
758 | |
759 | if (!MLX5_CAP_GEN_MAX(dev, log_max_current_uc_list_wr_supported)) |
760 | return; |
761 | |
762 | devl_params_unregister(devlink, params: mlx5_devlink_max_uc_list_params, |
763 | ARRAY_SIZE(mlx5_devlink_max_uc_list_params)); |
764 | } |
765 | |
766 | #define MLX5_TRAP_DROP(_id, _group_id) \ |
767 | DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ |
768 | DEVLINK_TRAP_GROUP_GENERIC_ID_##_group_id, \ |
769 | DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) |
770 | |
771 | static const struct devlink_trap mlx5_traps_arr[] = { |
772 | MLX5_TRAP_DROP(INGRESS_VLAN_FILTER, L2_DROPS), |
773 | MLX5_TRAP_DROP(DMAC_FILTER, L2_DROPS), |
774 | }; |
775 | |
776 | static const struct devlink_trap_group mlx5_trap_groups_arr[] = { |
777 | DEVLINK_TRAP_GROUP_GENERIC(L2_DROPS, 0), |
778 | }; |
779 | |
780 | int mlx5_devlink_traps_register(struct devlink *devlink) |
781 | { |
782 | struct mlx5_core_dev *core_dev = devlink_priv(devlink); |
783 | int err; |
784 | |
785 | err = devl_trap_groups_register(devlink, groups: mlx5_trap_groups_arr, |
786 | ARRAY_SIZE(mlx5_trap_groups_arr)); |
787 | if (err) |
788 | return err; |
789 | |
790 | err = devl_traps_register(devlink, traps: mlx5_traps_arr, ARRAY_SIZE(mlx5_traps_arr), |
791 | priv: &core_dev->priv); |
792 | if (err) |
793 | goto err_trap_group; |
794 | return 0; |
795 | |
796 | err_trap_group: |
797 | devl_trap_groups_unregister(devlink, groups: mlx5_trap_groups_arr, |
798 | ARRAY_SIZE(mlx5_trap_groups_arr)); |
799 | return err; |
800 | } |
801 | |
802 | void mlx5_devlink_traps_unregister(struct devlink *devlink) |
803 | { |
804 | devl_traps_unregister(devlink, traps: mlx5_traps_arr, ARRAY_SIZE(mlx5_traps_arr)); |
805 | devl_trap_groups_unregister(devlink, groups: mlx5_trap_groups_arr, |
806 | ARRAY_SIZE(mlx5_trap_groups_arr)); |
807 | } |
808 | |
809 | int mlx5_devlink_params_register(struct devlink *devlink) |
810 | { |
811 | int err; |
812 | |
813 | /* Here only the driver init params should be registered. |
814 | * Runtime params should be registered by the code which |
815 | * behaviour they configure. |
816 | */ |
817 | |
818 | err = devl_params_register(devlink, params: mlx5_devlink_params, |
819 | ARRAY_SIZE(mlx5_devlink_params)); |
820 | if (err) |
821 | return err; |
822 | |
823 | mlx5_devlink_set_params_init_values(devlink); |
824 | |
825 | err = mlx5_devlink_auxdev_params_register(devlink); |
826 | if (err) |
827 | goto auxdev_reg_err; |
828 | |
829 | err = mlx5_devlink_max_uc_list_params_register(devlink); |
830 | if (err) |
831 | goto max_uc_list_err; |
832 | |
833 | return 0; |
834 | |
835 | max_uc_list_err: |
836 | mlx5_devlink_auxdev_params_unregister(devlink); |
837 | auxdev_reg_err: |
838 | devl_params_unregister(devlink, params: mlx5_devlink_params, |
839 | ARRAY_SIZE(mlx5_devlink_params)); |
840 | return err; |
841 | } |
842 | |
843 | void mlx5_devlink_params_unregister(struct devlink *devlink) |
844 | { |
845 | mlx5_devlink_max_uc_list_params_unregister(devlink); |
846 | mlx5_devlink_auxdev_params_unregister(devlink); |
847 | devl_params_unregister(devlink, params: mlx5_devlink_params, |
848 | ARRAY_SIZE(mlx5_devlink_params)); |
849 | } |
850 | |