1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3
4 #include "lib/sd.h"
5 #include "../lag/lag.h"
6 #include "mlx5_core.h"
7 #include "lib/mlx5.h"
8 #include "devlink.h"
9 #include "eswitch.h"
10 #include "fs_cmd.h"
11 #include <linux/mlx5/eswitch.h>
12 #include <linux/mlx5/vport.h>
13 #include <linux/debugfs.h>
14
15 #define sd_info(__dev, format, ...) \
16 dev_info((__dev)->device, "Socket-Direct: " format, ##__VA_ARGS__)
17 #define sd_warn(__dev, format, ...) \
18 dev_warn((__dev)->device, "Socket-Direct: " format, ##__VA_ARGS__)
19
20 struct mlx5_sd {
21 u32 group_id;
22 u8 group_size;
23 struct mlx5_devcom_comp_dev *devcom;
24 struct dentry *dfs;
25 u8 state;
26 bool primary;
27 bool fw_silents_secondaries;
28 union {
29 struct { /* primary */
30 struct mlx5_core_dev *secondaries[MLX5_SD_MAX_GROUP_SZ - 1];
31 struct mlx5_flow_table *tx_ft;
32 /* Next index for secondary registration */
33 u8 next_secondary_idx;
34 };
35 struct { /* secondary */
36 struct mlx5_core_dev *primary_dev;
37 u32 alias_obj_id;
38 /* TX flow table root in switchdev (silent) config */
39 bool tx_root_silent;
40 };
41 };
42 };
43
44 enum mlx5_sd_state {
45 MLX5_SD_STATE_DOWN = 0,
46 MLX5_SD_STATE_UP,
47 };
48
mlx5_sd_get_group_size(struct mlx5_core_dev * dev)49 static int mlx5_sd_get_group_size(struct mlx5_core_dev *dev)
50 {
51 struct mlx5_sd *sd = mlx5_get_sd(dev);
52
53 if (!sd)
54 return 1;
55
56 return sd->group_size;
57 }
58
mlx5_sd_get_primary(struct mlx5_core_dev * dev)59 struct mlx5_core_dev *mlx5_sd_get_primary(struct mlx5_core_dev *dev)
60 {
61 struct mlx5_sd *sd = mlx5_get_sd(dev);
62
63 if (!sd)
64 return dev;
65
66 if (!mlx5_devcom_comp_is_ready(sd->devcom))
67 return NULL;
68
69 return sd->primary ? dev : sd->primary_dev;
70 }
71
mlx5_sd_get_devcom(struct mlx5_core_dev * dev)72 struct mlx5_devcom_comp_dev *mlx5_sd_get_devcom(struct mlx5_core_dev *dev)
73 {
74 struct mlx5_sd *sd = mlx5_get_sd(dev);
75
76 if (!sd)
77 return NULL;
78
79 return sd->devcom;
80 }
81
mlx5_sd_is_primary(struct mlx5_core_dev * dev)82 bool mlx5_sd_is_primary(struct mlx5_core_dev *dev)
83 {
84 struct mlx5_sd *sd = mlx5_get_sd(dev);
85
86 if (!sd)
87 return true;
88
89 return sd->primary;
90 }
91
mlx5_sd_pf_num_get(struct mlx5_core_dev * dev)92 int mlx5_sd_pf_num_get(struct mlx5_core_dev *dev)
93 {
94 struct mlx5_sd *sd = mlx5_get_sd(dev);
95 int pf_num = mlx5_get_dev_index(dev);
96 struct mlx5_core_dev *pos;
97 int i;
98
99 if (!sd)
100 return pf_num;
101
102 mlx5_devcom_comp_assert_locked(sd->devcom);
103 if (!mlx5_devcom_comp_is_ready(sd->devcom))
104 return -ENODEV;
105
106 mlx5_sd_for_each_dev(i, mlx5_sd_get_primary(dev), pos)
107 if (pos == dev)
108 break;
109
110 return pf_num * sd->group_size + i;
111 }
112
113 struct mlx5_core_dev *
mlx5_sd_primary_get_peer(struct mlx5_core_dev * primary,int idx)114 mlx5_sd_primary_get_peer(struct mlx5_core_dev *primary, int idx)
115 {
116 struct mlx5_sd *sd;
117
118 if (idx == 0)
119 return primary;
120
121 if (idx >= mlx5_sd_get_group_size(primary))
122 return NULL;
123
124 sd = mlx5_get_sd(primary);
125 return sd->secondaries[idx - 1];
126 }
127
mlx5_sd_ch_ix_get_dev_ix(struct mlx5_core_dev * dev,int ch_ix)128 int mlx5_sd_ch_ix_get_dev_ix(struct mlx5_core_dev *dev, int ch_ix)
129 {
130 if (is_mdev_switchdev_mode(dev))
131 return 0;
132
133 return ch_ix % mlx5_sd_get_group_size(dev);
134 }
135
mlx5_sd_ch_ix_get_vec_ix(struct mlx5_core_dev * dev,int ch_ix)136 int mlx5_sd_ch_ix_get_vec_ix(struct mlx5_core_dev *dev, int ch_ix)
137 {
138 if (is_mdev_switchdev_mode(dev))
139 return ch_ix;
140
141 return ch_ix / mlx5_sd_get_group_size(dev);
142 }
143
mlx5_sd_ch_ix_get_dev(struct mlx5_core_dev * primary,int ch_ix)144 struct mlx5_core_dev *mlx5_sd_ch_ix_get_dev(struct mlx5_core_dev *primary, int ch_ix)
145 {
146 int mdev_idx = mlx5_sd_ch_ix_get_dev_ix(primary, ch_ix);
147
148 return mlx5_sd_primary_get_peer(primary, mdev_idx);
149 }
150
ft_create_alias_supported(struct mlx5_core_dev * dev)151 static bool ft_create_alias_supported(struct mlx5_core_dev *dev)
152 {
153 u64 obj_allowed = MLX5_CAP_GEN_2_64(dev, allowed_object_for_other_vhca_access);
154 u32 obj_supp = MLX5_CAP_GEN_2(dev, cross_vhca_object_to_object_supported);
155
156 if (!(obj_supp &
157 MLX5_CROSS_VHCA_OBJ_TO_OBJ_SUPPORTED_LOCAL_FLOW_TABLE_ROOT_TO_REMOTE_FLOW_TABLE))
158 return false;
159
160 if (!(obj_allowed & MLX5_ALLOWED_OBJ_FOR_OTHER_VHCA_ACCESS_FLOW_TABLE))
161 return false;
162
163 return true;
164 }
165
mlx5_query_sd(struct mlx5_core_dev * dev,bool * sdm,u8 * group_size)166 static int mlx5_query_sd(struct mlx5_core_dev *dev, bool *sdm,
167 u8 *group_size)
168 {
169 u32 out[MLX5_ST_SZ_DW(mpir_reg)];
170 int err;
171
172 err = mlx5_query_mpir_reg(dev, out);
173 if (err)
174 return err;
175
176 *sdm = MLX5_GET(mpir_reg, out, sdm);
177 *group_size = MLX5_GET(mpir_reg, out, host_buses);
178
179 return 0;
180 }
181
mlx5_sd_group_id(struct mlx5_core_dev * dev,u8 sd_group)182 static u32 mlx5_sd_group_id(struct mlx5_core_dev *dev, u8 sd_group)
183 {
184 return (u32)((MLX5_CAP_GEN(dev, native_port_num) << 8) | sd_group);
185 }
186
mlx5_sd_caps_supported(struct mlx5_core_dev * dev,u8 group_size)187 static bool mlx5_sd_caps_supported(struct mlx5_core_dev *dev, u8 group_size)
188 {
189 /* Honor the SW implementation limit */
190 if (group_size > MLX5_SD_MAX_GROUP_SZ)
191 return false;
192
193 /* Disconnect secondaries from the network */
194 if (!MLX5_CAP_GEN(dev, eswitch_manager))
195 return false;
196 if (!MLX5_CAP_GEN(dev, silent_mode_set) &&
197 !MLX5_CAP_GEN(dev, silent_mode_query))
198 return false;
199
200 /* RX steering from primary to secondaries */
201 if (!MLX5_CAP_GEN(dev, cross_vhca_rqt))
202 return false;
203 if (group_size > MLX5_CAP_GEN_2(dev, max_rqt_vhca_id))
204 return false;
205
206 /* TX steering from secondaries to primary */
207 if (!ft_create_alias_supported(dev))
208 return false;
209 if (!MLX5_CAP_FLOWTABLE_NIC_TX(dev, reset_root_to_default))
210 return false;
211
212 return true;
213 }
214
mlx5_sd_is_supported(struct mlx5_core_dev * dev)215 bool mlx5_sd_is_supported(struct mlx5_core_dev *dev)
216 {
217 u8 group_size = U8_MAX, sd_group;
218 bool sdm;
219 int err;
220
221 /* Feature is currently implemented for PFs only */
222 if (!mlx5_core_is_pf(dev))
223 return false;
224
225 err = mlx5_query_nic_vport_sd_group(dev, &sd_group, &group_size);
226 if (err || !sd_group || group_size < MLX5_SD_MIN_GROUP_SZ)
227 return false;
228
229 if (group_size == U8_MAX) {
230 if (!MLX5_CAP_MCAM_REG(dev, mpir))
231 return false;
232
233 err = mlx5_query_sd(dev, &sdm, &group_size);
234 if (err || !sdm)
235 return false;
236 }
237
238 return mlx5_sd_caps_supported(dev, group_size);
239 }
240
sd_init(struct mlx5_core_dev * dev)241 static int sd_init(struct mlx5_core_dev *dev)
242 {
243 u8 group_size = U8_MAX, sd_group;
244 struct mlx5_sd *sd;
245 u32 group_id;
246 bool sdm;
247 int err;
248
249 /* Feature is currently implemented for PFs only */
250 if (!mlx5_core_is_pf(dev))
251 return 0;
252
253 err = mlx5_query_nic_vport_sd_group(dev, &sd_group, &group_size);
254 if (err)
255 return err;
256
257 if (!sd_group || group_size < MLX5_SD_MIN_GROUP_SZ)
258 return 0;
259
260 if (group_size == U8_MAX) {
261 if (!MLX5_CAP_MCAM_REG(dev, mpir))
262 return 0;
263
264 err = mlx5_query_sd(dev, &sdm, &group_size);
265 if (err)
266 return err;
267
268 if (!sdm)
269 return 0;
270 }
271 group_id = mlx5_sd_group_id(dev, sd_group);
272
273 if (!mlx5_sd_caps_supported(dev, group_size)) {
274 sd_warn(dev, "can't support requested netdev combining for group id 0x%x, skipping\n",
275 group_id);
276 return 0;
277 }
278
279 sd = kzalloc_obj(*sd);
280 if (!sd)
281 return -ENOMEM;
282
283 sd->group_size = group_size;
284 sd->group_id = group_id;
285
286 mlx5_set_sd(dev, sd);
287
288 return 0;
289 }
290
sd_cleanup(struct mlx5_core_dev * dev)291 static void sd_cleanup(struct mlx5_core_dev *dev)
292 {
293 struct mlx5_sd *sd = mlx5_get_sd(dev);
294
295 mlx5_set_sd(dev, NULL);
296 kfree(sd);
297 }
298
sd_lag_state_show(struct seq_file * file,void * priv)299 static int sd_lag_state_show(struct seq_file *file, void *priv)
300 {
301 struct mlx5_core_dev *dev = file->private;
302 struct mlx5_lag *ldev;
303 struct lag_func *pf;
304 bool active = false;
305 int i;
306
307 ldev = mlx5_lag_dev(dev);
308 if (!ldev)
309 return -EINVAL;
310
311 mutex_lock(&ldev->lock);
312 mlx5_ldev_for_each(i, 0, ldev) {
313 pf = mlx5_lag_pf(ldev, i);
314 if (pf->dev == dev) {
315 active = pf->sd_fdb_active;
316 break;
317 }
318 }
319 mutex_unlock(&ldev->lock);
320
321 seq_printf(file, "%s\n", active ? "active" : "disabled");
322 return 0;
323 }
324
325 DEFINE_SHOW_ATTRIBUTE(sd_lag_state);
326
327 /* SD LAG integration is optional. If LAG isn't available on this device
328 * (e.g. lag caps are off), or registering secondaries fails, just warn
329 * and continue - SD can operate without the LAG-side bookkeeping.
330 */
sd_lag_init(struct mlx5_core_dev * dev)331 static void sd_lag_init(struct mlx5_core_dev *dev)
332 {
333 struct mlx5_core_dev *primary = mlx5_sd_get_primary(dev);
334 struct mlx5_sd *sd = mlx5_get_sd(primary);
335 struct mlx5_core_dev *pos, *to;
336 struct mlx5_lag *ldev;
337 struct lag_func *pf;
338 int err;
339 int i;
340
341 ldev = mlx5_lag_dev(primary);
342 if (!ldev) {
343 sd_warn(primary, "%s: no ldev (LAG caps off?), skipping\n",
344 __func__);
345 return;
346 }
347
348 mutex_lock(&ldev->lock);
349 pf = mlx5_lag_pf_by_dev(ldev, primary);
350 if (!pf) {
351 sd_warn(primary, "%s: primary not registered in ldev, skipping\n",
352 __func__);
353 goto out;
354 }
355
356 pf->group_id = sd->group_id;
357
358 mlx5_sd_for_each_secondary(i, primary, pos) {
359 err = mlx5_ldev_add_mdev(ldev, pos, sd->group_id);
360 if (err) {
361 sd_warn(primary, "%s: failed to add secondary %s to ldev: %d\n",
362 __func__, dev_name(pos->device), err);
363 goto err;
364 }
365 }
366
367 out:
368 mutex_unlock(&ldev->lock);
369 return;
370
371 err:
372 to = pos;
373 mlx5_sd_for_each_secondary_to(i, primary, to, pos)
374 mlx5_ldev_remove_mdev(ldev, pos);
375 pf->group_id = 0;
376 mutex_unlock(&ldev->lock);
377 }
378
sd_lag_cleanup(struct mlx5_core_dev * dev)379 static void sd_lag_cleanup(struct mlx5_core_dev *dev)
380 {
381 struct mlx5_core_dev *primary = mlx5_sd_get_primary(dev);
382 struct mlx5_core_dev *pos;
383 struct mlx5_lag *ldev;
384 struct lag_func *pf;
385 int i;
386
387 ldev = mlx5_lag_dev(primary);
388 if (!ldev)
389 return;
390
391 mutex_lock(&ldev->lock);
392 mlx5_sd_for_each_secondary(i, primary, pos)
393 mlx5_ldev_remove_mdev(ldev, pos);
394
395 pf = mlx5_lag_pf_by_dev(ldev, primary);
396 if (pf)
397 pf->group_id = 0;
398 mutex_unlock(&ldev->lock);
399 }
400
401 enum {
402 SD_PRIMARY_SET,
403 SD_SECONDARIES_SET,
404 SD_FW_SILENT_CHECK,
405 };
406
sd_handle_fw_silent_check(struct mlx5_core_dev * dev,struct mlx5_core_dev * peer)407 static int sd_handle_fw_silent_check(struct mlx5_core_dev *dev,
408 struct mlx5_core_dev *peer)
409 {
410 struct mlx5_sd *peer_sd = mlx5_get_sd(peer);
411 struct mlx5_sd *sd = mlx5_get_sd(dev);
412 u8 dev_silent = 0, peer_silent = 0;
413 int err;
414
415 if (peer_sd->fw_silents_secondaries) {
416 sd->fw_silents_secondaries = true;
417 return 0;
418 }
419
420 err = mlx5_fs_cmd_query_l2table_silent(dev, &dev_silent);
421 if (err) {
422 sd_warn(dev, "Failed to query silent mode for dev: %d\n", err);
423 return err;
424 }
425
426 err = mlx5_fs_cmd_query_l2table_silent(peer, &peer_silent);
427 if (err) {
428 sd_warn(dev, "Failed to query silent mode for peer: %d\n", err);
429 return err;
430 }
431
432 if (dev_silent || peer_silent) {
433 sd->fw_silents_secondaries = true;
434 peer_sd->fw_silents_secondaries = true;
435 sd_info(dev, "FW indicates at least one device is silent\n");
436 }
437 return 0;
438 }
439
sd_handle_primary_set(struct mlx5_core_dev * dev,struct mlx5_core_dev * peer)440 static int sd_handle_primary_set(struct mlx5_core_dev *dev,
441 struct mlx5_core_dev *peer)
442 {
443 struct mlx5_sd *peer_sd = mlx5_get_sd(peer);
444 struct mlx5_sd *sd = mlx5_get_sd(dev);
445 struct mlx5_core_dev *candidate;
446 struct mlx5_sd *candidate_sd;
447 bool dev_should_be_primary;
448
449 /* Peer is the device that being sent to all the other devices in the
450 * group. Hence, use peer to get the candidate device.
451 */
452 candidate = peer_sd->primary ? peer : peer_sd->primary_dev;
453
454 if (sd->fw_silents_secondaries) {
455 u8 candidate_silent = 0;
456 int err;
457
458 err = mlx5_fs_cmd_query_l2table_silent(candidate,
459 &candidate_silent);
460 if (err) {
461 sd_warn(candidate, "Failed to query silent mode for dev: %d\n",
462 err);
463 return err;
464 }
465 /* Candidate is silent, dev should be primary */
466 dev_should_be_primary = candidate_silent;
467 } else {
468 /* No FW silent mode, use bus number */
469 dev_should_be_primary =
470 dev->pdev->bus->number < candidate->pdev->bus->number;
471 }
472
473 if (!dev_should_be_primary)
474 return 0;
475
476 candidate_sd = mlx5_get_sd(candidate);
477
478 sd->primary = true;
479 candidate_sd->primary = false;
480 candidate_sd->primary_dev = dev;
481 peer_sd->primary = false;
482 peer_sd->primary_dev = dev;
483 return 0;
484 }
485
sd_handle_secondaries_set(struct mlx5_core_dev * dev,struct mlx5_core_dev * peer)486 static void sd_handle_secondaries_set(struct mlx5_core_dev *dev,
487 struct mlx5_core_dev *peer)
488 {
489 struct mlx5_sd *peer_sd = mlx5_get_sd(peer);
490 struct mlx5_sd *sd = mlx5_get_sd(dev);
491 u8 idx;
492
493 /* Primary has nothing to register with itself. */
494 if (sd->primary)
495 return;
496
497 /* dev is a secondary device, peer is the primary device.
498 * Secondary registers itself with the primary.
499 */
500 idx = peer_sd->next_secondary_idx++;
501 peer_sd->secondaries[idx] = dev;
502 sd->primary_dev = peer;
503 }
504
mlx5_sd_devcom_event(int event,void * my_data,void * event_data)505 static int mlx5_sd_devcom_event(int event, void *my_data, void *event_data)
506 {
507 struct mlx5_core_dev *peer = event_data;
508 struct mlx5_core_dev *dev = my_data;
509
510 switch (event) {
511 case SD_FW_SILENT_CHECK:
512 return sd_handle_fw_silent_check(dev, peer);
513 case SD_PRIMARY_SET:
514 return sd_handle_primary_set(dev, peer);
515 case SD_SECONDARIES_SET:
516 sd_handle_secondaries_set(dev, peer);
517 return 0;
518 }
519
520 return 0;
521 }
522
sd_register(struct mlx5_core_dev * dev)523 static int sd_register(struct mlx5_core_dev *dev)
524 {
525 struct mlx5_devcom_match_attr attr = {};
526 struct mlx5_devcom_comp_dev *devcom;
527 struct mlx5_core_dev *primary;
528 struct mlx5_sd *primary_sd;
529 struct mlx5_sd *sd;
530 int err;
531
532 sd = mlx5_get_sd(dev);
533 attr.key.val = sd->group_id;
534 attr.flags = MLX5_DEVCOM_MATCH_FLAGS_NS;
535 attr.net = mlx5_core_net(dev);
536 devcom = mlx5_devcom_register_component(dev->priv.devc,
537 MLX5_DEVCOM_SD_GROUP,
538 &attr, mlx5_sd_devcom_event,
539 dev);
540 if (!devcom)
541 return -EINVAL;
542
543 sd->devcom = devcom;
544
545 mlx5_devcom_comp_lock(devcom);
546 if (mlx5_devcom_comp_get_size(devcom) != sd->group_size ||
547 mlx5_devcom_comp_is_ready(devcom))
548 goto out;
549
550 /* If silent mode query is supported, ask each device whether it is
551 * silent and propagate the result to the whole group. In each group
552 * only one device is not silent
553 */
554 if (MLX5_CAP_GEN(dev, silent_mode_query)) {
555 err = mlx5_devcom_locked_send_event(devcom, SD_FW_SILENT_CHECK,
556 SD_FW_SILENT_CHECK, dev);
557 if (err)
558 goto err_devcom_unreg;
559 }
560
561 /* Send SD_PRIMARY_SET event with this device.
562 * All peers will receive this event and compare to this device.
563 * If fw_silents_secondaries is set, choose non-silent device.
564 * Otherwise use bus number.
565 */
566 sd->primary = true;
567 err = mlx5_devcom_locked_send_event(devcom, SD_PRIMARY_SET,
568 SD_PRIMARY_SET, dev);
569 if (err)
570 goto err_devcom_unreg;
571
572 /* Broadcast SD_SECONDARIES_SET. Each non-sender peer's handler runs;
573 * the primary's handler returns early so only secondaries register.
574 */
575 primary = sd->primary ? dev : sd->primary_dev;
576 if (!sd->primary)
577 sd_handle_secondaries_set(dev, primary);
578 mlx5_devcom_locked_send_event(devcom, SD_SECONDARIES_SET,
579 DEVCOM_CANT_FAIL, primary);
580
581 primary_sd = mlx5_get_sd(primary);
582 if (primary_sd->next_secondary_idx + 1 == sd->group_size)
583 mlx5_devcom_comp_set_ready(devcom, true);
584 out:
585 mlx5_devcom_comp_unlock(devcom);
586 return 0;
587
588 err_devcom_unreg:
589 mlx5_devcom_comp_unlock(devcom);
590 mlx5_devcom_unregister_component(devcom);
591 return err;
592 }
593
sd_unregister(struct mlx5_core_dev * dev)594 static void sd_unregister(struct mlx5_core_dev *dev)
595 {
596 struct mlx5_sd *sd = mlx5_get_sd(dev);
597
598 mlx5_devcom_unregister_component(sd->devcom);
599 }
600
sd_cmd_set_primary(struct mlx5_core_dev * primary,u8 * alias_key)601 static int sd_cmd_set_primary(struct mlx5_core_dev *primary, u8 *alias_key)
602 {
603 struct mlx5_cmd_allow_other_vhca_access_attr allow_attr = {};
604 struct mlx5_sd *sd = mlx5_get_sd(primary);
605 struct mlx5_flow_table_attr ft_attr = {};
606 struct mlx5_flow_namespace *nic_ns;
607 struct mlx5_flow_table *ft;
608 int err;
609
610 nic_ns = mlx5_get_flow_namespace(primary, MLX5_FLOW_NAMESPACE_EGRESS);
611 if (!nic_ns)
612 return -EOPNOTSUPP;
613
614 ft = mlx5_create_flow_table(nic_ns, &ft_attr);
615 if (IS_ERR(ft)) {
616 err = PTR_ERR(ft);
617 return err;
618 }
619 sd->tx_ft = ft;
620 memcpy(allow_attr.access_key, alias_key, ACCESS_KEY_LEN);
621 allow_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
622 allow_attr.obj_id = (ft->type << FT_ID_FT_TYPE_OFFSET) | ft->id;
623
624 err = mlx5_cmd_allow_other_vhca_access(primary, &allow_attr);
625 if (err) {
626 mlx5_core_err(primary, "Failed to allow other vhca access err=%d\n",
627 err);
628 mlx5_destroy_flow_table(ft);
629 return err;
630 }
631
632 return 0;
633 }
634
sd_cmd_unset_primary(struct mlx5_core_dev * primary)635 static void sd_cmd_unset_primary(struct mlx5_core_dev *primary)
636 {
637 struct mlx5_sd *sd = mlx5_get_sd(primary);
638
639 mlx5_destroy_flow_table(sd->tx_ft);
640 }
641
sd_secondary_create_alias_ft(struct mlx5_core_dev * secondary,struct mlx5_core_dev * primary,struct mlx5_flow_table * ft,u32 * obj_id,u8 * alias_key)642 static int sd_secondary_create_alias_ft(struct mlx5_core_dev *secondary,
643 struct mlx5_core_dev *primary,
644 struct mlx5_flow_table *ft,
645 u32 *obj_id, u8 *alias_key)
646 {
647 u32 aliased_object_id = (ft->type << FT_ID_FT_TYPE_OFFSET) | ft->id;
648 u16 vhca_id_to_be_accessed = MLX5_CAP_GEN(primary, vhca_id);
649 struct mlx5_cmd_alias_obj_create_attr alias_attr = {};
650 int ret;
651
652 memcpy(alias_attr.access_key, alias_key, ACCESS_KEY_LEN);
653 alias_attr.obj_id = aliased_object_id;
654 alias_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
655 alias_attr.vhca_id = vhca_id_to_be_accessed;
656 ret = mlx5_cmd_alias_obj_create(secondary, &alias_attr, obj_id);
657 if (ret) {
658 mlx5_core_err(secondary, "Failed to create alias object err=%d\n",
659 ret);
660 return ret;
661 }
662
663 return 0;
664 }
665
sd_secondary_destroy_alias_ft(struct mlx5_core_dev * secondary)666 static void sd_secondary_destroy_alias_ft(struct mlx5_core_dev *secondary)
667 {
668 struct mlx5_sd *sd = mlx5_get_sd(secondary);
669
670 mlx5_cmd_alias_obj_destroy(secondary, sd->alias_obj_id,
671 MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
672 }
673
mlx5_sd_secondary_conf_tx_root(struct mlx5_core_dev * secondary,bool disconnect)674 static int mlx5_sd_secondary_conf_tx_root(struct mlx5_core_dev *secondary,
675 bool disconnect)
676 {
677 struct mlx5_sd *sd = mlx5_get_sd(secondary);
678 int err;
679
680 /* Idempotent: skip if TX root is already in the requested state. */
681 if (sd->tx_root_silent == disconnect)
682 return 0;
683
684 if (disconnect)
685 err = mlx5_fs_cmd_set_tx_flow_table_root(secondary, 0, true);
686 else
687 err = mlx5_fs_cmd_set_tx_flow_table_root(secondary,
688 sd->alias_obj_id,
689 false);
690 if (err)
691 return err;
692
693 sd->tx_root_silent = disconnect;
694 return 0;
695 }
696
sd_cmd_set_secondary(struct mlx5_core_dev * secondary,struct mlx5_core_dev * primary,u8 * alias_key)697 static int sd_cmd_set_secondary(struct mlx5_core_dev *secondary,
698 struct mlx5_core_dev *primary,
699 u8 *alias_key)
700 {
701 struct mlx5_sd *primary_sd = mlx5_get_sd(primary);
702 struct mlx5_sd *sd = mlx5_get_sd(secondary);
703 int err;
704
705 if (!primary_sd->fw_silents_secondaries) {
706 err = mlx5_fs_cmd_set_l2table_entry_silent(secondary, 1);
707 if (err)
708 return err;
709 }
710
711 err = sd_secondary_create_alias_ft(secondary, primary, primary_sd->tx_ft,
712 &sd->alias_obj_id, alias_key);
713 if (err)
714 goto err_unset_silent;
715
716 err = mlx5_fs_cmd_set_tx_flow_table_root(secondary, sd->alias_obj_id,
717 false);
718 if (err)
719 goto err_destroy_alias_ft;
720 sd->tx_root_silent = false;
721
722 return 0;
723
724 err_destroy_alias_ft:
725 sd_secondary_destroy_alias_ft(secondary);
726 err_unset_silent:
727 if (!primary_sd->fw_silents_secondaries)
728 mlx5_fs_cmd_set_l2table_entry_silent(secondary, 0);
729 return err;
730 }
731
sd_cmd_unset_secondary(struct mlx5_core_dev * secondary)732 static void sd_cmd_unset_secondary(struct mlx5_core_dev *secondary)
733 {
734 struct mlx5_sd *primary_sd;
735
736 primary_sd = mlx5_get_sd(mlx5_sd_get_primary(secondary));
737 mlx5_sd_secondary_conf_tx_root(secondary, true);
738 sd_secondary_destroy_alias_ft(secondary);
739 if (!primary_sd->fw_silents_secondaries)
740 mlx5_fs_cmd_set_l2table_entry_silent(secondary, 0);
741 }
742
sd_print_group(struct mlx5_core_dev * primary)743 static void sd_print_group(struct mlx5_core_dev *primary)
744 {
745 struct mlx5_sd *sd = mlx5_get_sd(primary);
746 struct mlx5_core_dev *pos;
747 int i;
748
749 sd_info(primary, "group id %#x, primary %s, vhca %#x\n",
750 sd->group_id, pci_name(primary->pdev),
751 MLX5_CAP_GEN(primary, vhca_id));
752 mlx5_sd_for_each_secondary(i, primary, pos)
753 sd_info(primary, "group id %#x, secondary_%d %s, vhca %#x\n",
754 sd->group_id, i - 1, pci_name(pos->pdev),
755 MLX5_CAP_GEN(pos, vhca_id));
756 }
757
dev_read(struct file * filp,char __user * buf,size_t count,loff_t * pos)758 static ssize_t dev_read(struct file *filp, char __user *buf, size_t count,
759 loff_t *pos)
760 {
761 struct mlx5_core_dev *dev;
762 char tbuf[32];
763 int ret;
764
765 dev = filp->private_data;
766 ret = snprintf(tbuf, sizeof(tbuf), "%s vhca %#x\n", pci_name(dev->pdev),
767 MLX5_CAP_GEN(dev, vhca_id));
768
769 return simple_read_from_buffer(buf, count, pos, tbuf, ret);
770 }
771
772 static const struct file_operations dev_fops = {
773 .owner = THIS_MODULE,
774 .open = simple_open,
775 .read = dev_read,
776 };
777
mlx5_sd_init(struct mlx5_core_dev * dev)778 int mlx5_sd_init(struct mlx5_core_dev *dev)
779 {
780 struct mlx5_core_dev *primary, *pos, *to;
781 struct mlx5_sd *sd = mlx5_get_sd(dev);
782 u8 alias_key[ACCESS_KEY_LEN];
783 struct mlx5_sd *primary_sd;
784 int err, i;
785
786 err = sd_init(dev);
787 if (err)
788 return err;
789
790 sd = mlx5_get_sd(dev);
791 if (!sd)
792 return 0;
793
794 err = sd_register(dev);
795 if (err)
796 goto err_sd_cleanup;
797
798 mlx5_devcom_comp_lock(sd->devcom);
799 if (!mlx5_devcom_comp_is_ready(sd->devcom))
800 goto out;
801
802 primary = mlx5_sd_get_primary(dev);
803 if (!primary)
804 goto out;
805
806 primary_sd = mlx5_get_sd(primary);
807 if (primary_sd->state != MLX5_SD_STATE_DOWN)
808 goto out;
809
810 for (i = 0; i < ACCESS_KEY_LEN; i++)
811 alias_key[i] = get_random_u8();
812
813 err = sd_cmd_set_primary(primary, alias_key);
814 if (err)
815 goto err_sd_unregister;
816
817 mlx5_sd_for_each_secondary(i, primary, pos) {
818 err = sd_cmd_set_secondary(pos, primary, alias_key);
819 if (err)
820 goto err_unset_secondaries;
821 }
822
823 sd_lag_init(primary);
824
825 primary_sd->dfs =
826 debugfs_create_dir("multi-pf",
827 mlx5_debugfs_get_dev_root(primary));
828 mlx5_sd_for_each_secondary(i, primary, pos) {
829 char name[32];
830
831 snprintf(name, sizeof(name), "secondary_%d", i - 1);
832 debugfs_create_file(name, 0400, primary_sd->dfs, pos,
833 &dev_fops);
834 }
835
836 debugfs_create_file("sd_lag_state", 0400, primary_sd->dfs, primary,
837 &sd_lag_state_fops);
838 debugfs_create_x32("group_id", 0400, primary_sd->dfs,
839 &primary_sd->group_id);
840 debugfs_create_file("primary", 0400, primary_sd->dfs, primary,
841 &dev_fops);
842
843 sd_info(primary, "group id %#x, size %d, combined\n",
844 sd->group_id, mlx5_devcom_comp_get_size(sd->devcom));
845 sd_print_group(primary);
846
847 primary_sd->state = MLX5_SD_STATE_UP;
848 out:
849 mlx5_devcom_comp_unlock(sd->devcom);
850 return 0;
851
852 err_unset_secondaries:
853 to = pos;
854 mlx5_sd_for_each_secondary_to(i, primary, to, pos)
855 sd_cmd_unset_secondary(pos);
856 sd_cmd_unset_primary(primary);
857 err_sd_unregister:
858 mlx5_sd_for_each_secondary(i, primary, pos) {
859 struct mlx5_sd *peer_sd = mlx5_get_sd(pos);
860
861 primary_sd->secondaries[i - 1] = NULL;
862 peer_sd->primary_dev = NULL;
863 }
864 primary_sd->primary = false;
865 primary_sd->next_secondary_idx = 0;
866 mlx5_devcom_comp_set_ready(sd->devcom, false);
867 mlx5_devcom_comp_unlock(sd->devcom);
868 sd_unregister(dev);
869 err_sd_cleanup:
870 sd_cleanup(dev);
871 return err;
872 }
873
mlx5_sd_cleanup(struct mlx5_core_dev * dev)874 void mlx5_sd_cleanup(struct mlx5_core_dev *dev)
875 {
876 struct mlx5_sd *sd = mlx5_get_sd(dev);
877 struct mlx5_core_dev *primary, *pos;
878 struct mlx5_sd *primary_sd;
879 int i;
880
881 if (!sd)
882 return;
883
884 mlx5_devcom_comp_lock(sd->devcom);
885 if (!mlx5_devcom_comp_is_ready(sd->devcom))
886 goto out_unlock;
887
888 primary = mlx5_sd_get_primary(dev);
889 if (!primary)
890 goto out_ready_false;
891
892 primary_sd = mlx5_get_sd(primary);
893 if (primary_sd->state != MLX5_SD_STATE_UP)
894 goto out_clear_peers;
895
896 debugfs_remove_recursive(primary_sd->dfs);
897 primary_sd->dfs = NULL;
898 sd_lag_cleanup(primary);
899 mlx5_sd_for_each_secondary(i, primary, pos)
900 sd_cmd_unset_secondary(pos);
901 sd_cmd_unset_primary(primary);
902
903 sd_info(primary, "group id %#x, uncombined\n", sd->group_id);
904 primary_sd->state = MLX5_SD_STATE_DOWN;
905 out_clear_peers:
906 mlx5_sd_for_each_secondary(i, primary, pos) {
907 struct mlx5_sd *peer_sd = mlx5_get_sd(pos);
908
909 primary_sd->secondaries[i - 1] = NULL;
910 peer_sd->primary_dev = NULL;
911 }
912 primary_sd->primary = false;
913 primary_sd->next_secondary_idx = 0;
914 out_ready_false:
915 mlx5_devcom_comp_set_ready(sd->devcom, false);
916 out_unlock:
917 mlx5_devcom_comp_unlock(sd->devcom);
918 sd_unregister(dev);
919 sd_cleanup(dev);
920 }
921
922 /* Lock order:
923 * primary: actual_adev_lock -> SD devcom comp lock
924 * secondary: SD devcom comp lock -> (drop) -> actual_adev_lock
925 * The two locks are never held together, so no ABBA.
926 */
mlx5_sd_get_adev(struct mlx5_core_dev * dev,struct auxiliary_device * adev,int idx)927 struct auxiliary_device *mlx5_sd_get_adev(struct mlx5_core_dev *dev,
928 struct auxiliary_device *adev,
929 int idx)
930 {
931 struct mlx5_sd *sd = mlx5_get_sd(dev);
932 struct mlx5_core_dev *primary;
933 struct mlx5_adev *primary_adev;
934
935 if (!sd)
936 return adev;
937
938 mlx5_devcom_comp_lock(sd->devcom);
939 if (!mlx5_devcom_comp_is_ready(sd->devcom)) {
940 mlx5_devcom_comp_unlock(sd->devcom);
941 return NULL;
942 }
943
944 primary = mlx5_sd_get_primary(dev);
945 if (!primary || dev == primary) {
946 mlx5_devcom_comp_unlock(sd->devcom);
947 return adev;
948 }
949
950 primary_adev = primary->priv.adev[idx];
951 get_device(&primary_adev->adev.dev);
952 mlx5_devcom_comp_unlock(sd->devcom);
953
954 device_lock(&primary_adev->adev.dev);
955 /* Primary may have completed remove between dropping devcom and
956 * acquiring device_lock; recheck.
957 */
958 if (!mlx5_devcom_comp_is_ready(sd->devcom)) {
959 device_unlock(&primary_adev->adev.dev);
960 put_device(&primary_adev->adev.dev);
961 return NULL;
962 }
963 return &primary_adev->adev;
964 }
965
966 #ifdef CONFIG_MLX5_ESWITCH
967 /* All SD members must have completed esw_offloads_enable (i.e., reached
968 * mlx5_esw_offloads_devcom_init) and become eswitch-peers of the primary.
969 * Until then, mlx5_eswitch_is_peer() returns false for the not-yet-paired
970 * member and shared_fdb_supported_filter would reject. When all PFs transition
971 * in parallel, only the last one to finish satisfies this gate; the earlier
972 * ones return 0 silently here.
973 */
mlx5_sd_all_paired(struct mlx5_core_dev * primary)974 static bool mlx5_sd_all_paired(struct mlx5_core_dev *primary)
975 {
976 struct mlx5_eswitch *primary_esw = primary->priv.eswitch;
977 struct mlx5_core_dev *pos;
978 int i;
979
980 mlx5_sd_for_each_secondary(i, primary, pos) {
981 if (!mlx5_eswitch_is_peer(primary_esw, pos->priv.eswitch))
982 return false;
983 }
984 return true;
985 }
986
mlx5_sd_activate_shared_fdb(struct mlx5_core_dev * primary)987 static void mlx5_sd_activate_shared_fdb(struct mlx5_core_dev *primary)
988 {
989 struct mlx5_sd *sd = mlx5_get_sd(primary);
990 struct mlx5_core_dev *pos;
991 struct mlx5_lag *ldev;
992 struct lag_func *pf;
993 int err;
994 int i;
995
996 ldev = mlx5_lag_dev(primary);
997 if (!ldev) {
998 sd_warn(primary, "Shared FDB MUST have ldev\n");
999 return;
1000 }
1001
1002 mutex_lock(&ldev->lock);
1003
1004 if (ldev->mode_changes_in_progress)
1005 goto unlock;
1006
1007 if (!mlx5_sd_all_paired(primary))
1008 goto unlock;
1009
1010 /* Check if SD FDB is already active for this group */
1011 mlx5_lag_for_each(i, 0, ldev, sd->group_id) {
1012 pf = mlx5_lag_pf(ldev, i);
1013 if (pf->sd_fdb_active)
1014 goto unlock;
1015 break;
1016 }
1017
1018 if (!mlx5_lag_shared_fdb_supported_filter(ldev, sd->group_id)) {
1019 sd_warn(primary, "Shared FDB not supported\n");
1020 goto unlock;
1021 }
1022
1023 /* Initialize vport metadata for all group devices. This is deferred
1024 * from esw_offloads_enable() because mlx5_sd_pf_num_get() requires
1025 * the SD group to be ready.
1026 */
1027 mlx5_sd_for_each_dev(i, primary, pos) {
1028 struct mlx5_eswitch *esw = pos->priv.eswitch;
1029
1030 err = mlx5_esw_offloads_init_deferred_metadata(esw);
1031 if (err) {
1032 sd_warn(primary, "Failed to init metadata for %s: %d\n",
1033 dev_name(pos->device), err);
1034 goto unlock;
1035 }
1036 }
1037
1038 err = mlx5_lag_shared_fdb_create(ldev, NULL, 0, sd->group_id);
1039 if (err)
1040 sd_warn(primary, "Failed to create shared FDB: %d\n", err);
1041 else
1042 sd_info(primary, "Shared FDB created\n");
1043
1044 unlock:
1045 mutex_unlock(&ldev->lock);
1046 }
1047
mlx5_sd_eswitch_mode_set(struct mlx5_core_dev * dev,u16 mlx5_mode)1048 void mlx5_sd_eswitch_mode_set(struct mlx5_core_dev *dev, u16 mlx5_mode)
1049 {
1050 struct mlx5_core_dev *primary;
1051 struct mlx5_sd *sd;
1052 int err;
1053
1054 sd = mlx5_get_sd(dev);
1055 if (!sd || !mlx5_devcom_comp_is_ready(sd->devcom))
1056 return;
1057
1058 mlx5_devcom_comp_lock(sd->devcom);
1059 if (!mlx5_devcom_comp_is_ready(sd->devcom))
1060 goto unlock;
1061
1062 primary = mlx5_sd_get_primary(dev);
1063
1064 /* Secondary devices need TX root reconfiguration */
1065 if (dev != primary) {
1066 bool disconnect = (mlx5_mode == MLX5_ESWITCH_OFFLOADS);
1067
1068 err = mlx5_sd_secondary_conf_tx_root(dev, disconnect);
1069 if (err) {
1070 sd_warn(dev, "Failed to set TX root: %d\n", err);
1071 goto unlock;
1072 }
1073 }
1074
1075 /* Try to activate shared FDB when all devices are in switchdev.
1076 * Shared FDB is optional - failure here doesn't fail the transition.
1077 */
1078 if (mlx5_mode == MLX5_ESWITCH_OFFLOADS)
1079 mlx5_sd_activate_shared_fdb(primary);
1080
1081 unlock:
1082 mlx5_devcom_comp_unlock(sd->devcom);
1083 }
1084
1085 #endif /* CONFIG_MLX5_ESWITCH */
1086
mlx5_sd_put_adev(struct auxiliary_device * actual_adev,struct auxiliary_device * adev)1087 void mlx5_sd_put_adev(struct auxiliary_device *actual_adev,
1088 struct auxiliary_device *adev)
1089 {
1090 if (actual_adev != adev) {
1091 device_unlock(&actual_adev->dev);
1092 put_device(&actual_adev->dev);
1093 }
1094 }
1095