]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - drivers/net/ethernet/mellanox/mlx5/core/lib/sd.c
net/mlx5: SD, Implement steering for primary and secondaries
[thirdparty/kernel/stable.git] / drivers / net / ethernet / mellanox / mlx5 / core / lib / sd.c
CommitLineData
4a04a31f
TT
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 "mlx5_core.h"
63b9ce94 6#include "lib/mlx5.h"
605fcce3 7#include "fs_cmd.h"
63b9ce94 8#include <linux/mlx5/vport.h>
4a04a31f
TT
9
10#define sd_info(__dev, format, ...) \
11 dev_info((__dev)->device, "Socket-Direct: " format, ##__VA_ARGS__)
12#define sd_warn(__dev, format, ...) \
13 dev_warn((__dev)->device, "Socket-Direct: " format, ##__VA_ARGS__)
14
15struct mlx5_sd {
63b9ce94
TT
16 u32 group_id;
17 u8 host_buses;
a45af9a9
TT
18 struct mlx5_devcom_comp_dev *devcom;
19 bool primary;
20 union {
21 struct { /* primary */
22 struct mlx5_core_dev *secondaries[MLX5_SD_MAX_GROUP_SZ - 1];
605fcce3 23 struct mlx5_flow_table *tx_ft;
a45af9a9
TT
24 };
25 struct { /* secondary */
26 struct mlx5_core_dev *primary_dev;
605fcce3 27 u32 alias_obj_id;
a45af9a9
TT
28 };
29 };
4a04a31f
TT
30};
31
32static int mlx5_sd_get_host_buses(struct mlx5_core_dev *dev)
33{
63b9ce94
TT
34 struct mlx5_sd *sd = mlx5_get_sd(dev);
35
36 if (!sd)
37 return 1;
38
39 return sd->host_buses;
4a04a31f
TT
40}
41
a45af9a9
TT
42static struct mlx5_core_dev *mlx5_sd_get_primary(struct mlx5_core_dev *dev)
43{
44 struct mlx5_sd *sd = mlx5_get_sd(dev);
45
46 if (!sd)
47 return dev;
48
49 return sd->primary ? dev : sd->primary_dev;
50}
51
4a04a31f
TT
52struct mlx5_core_dev *
53mlx5_sd_primary_get_peer(struct mlx5_core_dev *primary, int idx)
54{
a45af9a9
TT
55 struct mlx5_sd *sd;
56
4a04a31f
TT
57 if (idx == 0)
58 return primary;
59
a45af9a9
TT
60 if (idx >= mlx5_sd_get_host_buses(primary))
61 return NULL;
62
63 sd = mlx5_get_sd(primary);
64 return sd->secondaries[idx - 1];
4a04a31f
TT
65}
66
67int mlx5_sd_ch_ix_get_dev_ix(struct mlx5_core_dev *dev, int ch_ix)
68{
69 return ch_ix % mlx5_sd_get_host_buses(dev);
70}
71
72int mlx5_sd_ch_ix_get_vec_ix(struct mlx5_core_dev *dev, int ch_ix)
73{
74 return ch_ix / mlx5_sd_get_host_buses(dev);
75}
76
77struct mlx5_core_dev *mlx5_sd_ch_ix_get_dev(struct mlx5_core_dev *primary, int ch_ix)
78{
79 int mdev_idx = mlx5_sd_ch_ix_get_dev_ix(primary, ch_ix);
80
81 return mlx5_sd_primary_get_peer(primary, mdev_idx);
82}
83
605fcce3
TT
84static bool ft_create_alias_supported(struct mlx5_core_dev *dev)
85{
86 u64 obj_allowed = MLX5_CAP_GEN_2_64(dev, allowed_object_for_other_vhca_access);
87 u32 obj_supp = MLX5_CAP_GEN_2(dev, cross_vhca_object_to_object_supported);
88
89 if (!(obj_supp &
90 MLX5_CROSS_VHCA_OBJ_TO_OBJ_SUPPORTED_LOCAL_FLOW_TABLE_ROOT_TO_REMOTE_FLOW_TABLE))
91 return false;
92
93 if (!(obj_allowed & MLX5_ALLOWED_OBJ_FOR_OTHER_VHCA_ACCESS_FLOW_TABLE))
94 return false;
95
96 return true;
97}
98
63b9ce94
TT
99static bool mlx5_sd_is_supported(struct mlx5_core_dev *dev, u8 host_buses)
100{
101 /* Feature is currently implemented for PFs only */
102 if (!mlx5_core_is_pf(dev))
103 return false;
104
105 /* Honor the SW implementation limit */
106 if (host_buses > MLX5_SD_MAX_GROUP_SZ)
107 return false;
108
605fcce3
TT
109 /* Disconnect secondaries from the network */
110 if (!MLX5_CAP_GEN(dev, eswitch_manager))
111 return false;
112 if (!MLX5_CAP_GEN(dev, silent_mode))
113 return false;
114
115 /* RX steering from primary to secondaries */
116 if (!MLX5_CAP_GEN(dev, cross_vhca_rqt))
117 return false;
118 if (host_buses > MLX5_CAP_GEN_2(dev, max_rqt_vhca_id))
119 return false;
120
121 /* TX steering from secondaries to primary */
122 if (!ft_create_alias_supported(dev))
123 return false;
124 if (!MLX5_CAP_FLOWTABLE_NIC_TX(dev, reset_root_to_default))
125 return false;
126
63b9ce94
TT
127 return true;
128}
129
130static int mlx5_query_sd(struct mlx5_core_dev *dev, bool *sdm,
131 u8 *host_buses, u8 *sd_group)
132{
133 u32 out[MLX5_ST_SZ_DW(mpir_reg)];
134 int err;
135
136 err = mlx5_query_mpir_reg(dev, out);
137 if (err)
138 return err;
139
140 err = mlx5_query_nic_vport_sd_group(dev, sd_group);
141 if (err)
142 return err;
143
144 *sdm = MLX5_GET(mpir_reg, out, sdm);
145 *host_buses = MLX5_GET(mpir_reg, out, host_buses);
146
147 return 0;
148}
149
150static u32 mlx5_sd_group_id(struct mlx5_core_dev *dev, u8 sd_group)
151{
152 return (u32)((MLX5_CAP_GEN(dev, native_port_num) << 8) | sd_group);
153}
154
155static int sd_init(struct mlx5_core_dev *dev)
156{
157 u8 host_buses, sd_group;
158 struct mlx5_sd *sd;
159 u32 group_id;
160 bool sdm;
161 int err;
162
163 err = mlx5_query_sd(dev, &sdm, &host_buses, &sd_group);
164 if (err)
165 return err;
166
167 if (!sdm)
168 return 0;
169
170 if (!sd_group)
171 return 0;
172
173 group_id = mlx5_sd_group_id(dev, sd_group);
174
175 if (!mlx5_sd_is_supported(dev, host_buses)) {
176 sd_warn(dev, "can't support requested netdev combining for group id 0x%x), skipping\n",
177 group_id);
178 return 0;
179 }
180
181 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
182 if (!sd)
183 return -ENOMEM;
184
185 sd->host_buses = host_buses;
186 sd->group_id = group_id;
187
188 mlx5_set_sd(dev, sd);
189
190 return 0;
191}
192
193static void sd_cleanup(struct mlx5_core_dev *dev)
194{
195 struct mlx5_sd *sd = mlx5_get_sd(dev);
196
197 mlx5_set_sd(dev, NULL);
198 kfree(sd);
199}
200
a45af9a9
TT
201static int sd_register(struct mlx5_core_dev *dev)
202{
203 struct mlx5_devcom_comp_dev *devcom, *pos;
204 struct mlx5_core_dev *peer, *primary;
205 struct mlx5_sd *sd, *primary_sd;
206 int err, i;
207
208 sd = mlx5_get_sd(dev);
209 devcom = mlx5_devcom_register_component(dev->priv.devc, MLX5_DEVCOM_SD_GROUP,
210 sd->group_id, NULL, dev);
211 if (!devcom)
212 return -ENOMEM;
213
214 sd->devcom = devcom;
215
216 if (mlx5_devcom_comp_get_size(devcom) != sd->host_buses)
217 return 0;
218
219 mlx5_devcom_comp_lock(devcom);
220 mlx5_devcom_comp_set_ready(devcom, true);
221 mlx5_devcom_comp_unlock(devcom);
222
223 if (!mlx5_devcom_for_each_peer_begin(devcom)) {
224 err = -ENODEV;
225 goto err_devcom_unreg;
226 }
227
228 primary = dev;
229 mlx5_devcom_for_each_peer_entry(devcom, peer, pos)
230 if (peer->pdev->bus->number < primary->pdev->bus->number)
231 primary = peer;
232
233 primary_sd = mlx5_get_sd(primary);
234 primary_sd->primary = true;
235 i = 0;
236 /* loop the secondaries */
237 mlx5_devcom_for_each_peer_entry(primary_sd->devcom, peer, pos) {
238 struct mlx5_sd *peer_sd = mlx5_get_sd(peer);
239
240 primary_sd->secondaries[i++] = peer;
241 peer_sd->primary = false;
242 peer_sd->primary_dev = primary;
243 }
244
245 mlx5_devcom_for_each_peer_end(devcom);
246 return 0;
247
248err_devcom_unreg:
249 mlx5_devcom_comp_lock(sd->devcom);
250 mlx5_devcom_comp_set_ready(sd->devcom, false);
251 mlx5_devcom_comp_unlock(sd->devcom);
252 mlx5_devcom_unregister_component(sd->devcom);
253 return err;
254}
255
256static void sd_unregister(struct mlx5_core_dev *dev)
257{
258 struct mlx5_sd *sd = mlx5_get_sd(dev);
259
260 mlx5_devcom_comp_lock(sd->devcom);
261 mlx5_devcom_comp_set_ready(sd->devcom, false);
262 mlx5_devcom_comp_unlock(sd->devcom);
263 mlx5_devcom_unregister_component(sd->devcom);
264}
265
605fcce3
TT
266static int sd_cmd_set_primary(struct mlx5_core_dev *primary, u8 *alias_key)
267{
268 struct mlx5_cmd_allow_other_vhca_access_attr allow_attr = {};
269 struct mlx5_sd *sd = mlx5_get_sd(primary);
270 struct mlx5_flow_table_attr ft_attr = {};
271 struct mlx5_flow_namespace *nic_ns;
272 struct mlx5_flow_table *ft;
273 int err;
274
275 nic_ns = mlx5_get_flow_namespace(primary, MLX5_FLOW_NAMESPACE_EGRESS);
276 if (!nic_ns)
277 return -EOPNOTSUPP;
278
279 ft = mlx5_create_flow_table(nic_ns, &ft_attr);
280 if (IS_ERR(ft)) {
281 err = PTR_ERR(ft);
282 return err;
283 }
284 sd->tx_ft = ft;
285 memcpy(allow_attr.access_key, alias_key, ACCESS_KEY_LEN);
286 allow_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
287 allow_attr.obj_id = (ft->type << FT_ID_FT_TYPE_OFFSET) | ft->id;
288
289 err = mlx5_cmd_allow_other_vhca_access(primary, &allow_attr);
290 if (err) {
291 mlx5_core_err(primary, "Failed to allow other vhca access err=%d\n",
292 err);
293 mlx5_destroy_flow_table(ft);
294 return err;
295 }
296
297 return 0;
298}
299
300static void sd_cmd_unset_primary(struct mlx5_core_dev *primary)
301{
302 struct mlx5_sd *sd = mlx5_get_sd(primary);
303
304 mlx5_destroy_flow_table(sd->tx_ft);
305}
306
307static int sd_secondary_create_alias_ft(struct mlx5_core_dev *secondary,
308 struct mlx5_core_dev *primary,
309 struct mlx5_flow_table *ft,
310 u32 *obj_id, u8 *alias_key)
311{
312 u32 aliased_object_id = (ft->type << FT_ID_FT_TYPE_OFFSET) | ft->id;
313 u16 vhca_id_to_be_accessed = MLX5_CAP_GEN(primary, vhca_id);
314 struct mlx5_cmd_alias_obj_create_attr alias_attr = {};
315 int ret;
316
317 memcpy(alias_attr.access_key, alias_key, ACCESS_KEY_LEN);
318 alias_attr.obj_id = aliased_object_id;
319 alias_attr.obj_type = MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS;
320 alias_attr.vhca_id = vhca_id_to_be_accessed;
321 ret = mlx5_cmd_alias_obj_create(secondary, &alias_attr, obj_id);
322 if (ret) {
323 mlx5_core_err(secondary, "Failed to create alias object err=%d\n",
324 ret);
325 return ret;
326 }
327
328 return 0;
329}
330
331static void sd_secondary_destroy_alias_ft(struct mlx5_core_dev *secondary)
332{
333 struct mlx5_sd *sd = mlx5_get_sd(secondary);
334
335 mlx5_cmd_alias_obj_destroy(secondary, sd->alias_obj_id,
336 MLX5_GENERAL_OBJECT_TYPES_FLOW_TABLE_ALIAS);
337}
338
339static int sd_cmd_set_secondary(struct mlx5_core_dev *secondary,
340 struct mlx5_core_dev *primary,
341 u8 *alias_key)
342{
343 struct mlx5_sd *primary_sd = mlx5_get_sd(primary);
344 struct mlx5_sd *sd = mlx5_get_sd(secondary);
345 int err;
346
347 err = mlx5_fs_cmd_set_l2table_entry_silent(secondary, 1);
348 if (err)
349 return err;
350
351 err = sd_secondary_create_alias_ft(secondary, primary, primary_sd->tx_ft,
352 &sd->alias_obj_id, alias_key);
353 if (err)
354 goto err_unset_silent;
355
356 err = mlx5_fs_cmd_set_tx_flow_table_root(secondary, sd->alias_obj_id, false);
357 if (err)
358 goto err_destroy_alias_ft;
359
360 return 0;
361
362err_destroy_alias_ft:
363 sd_secondary_destroy_alias_ft(secondary);
364err_unset_silent:
365 mlx5_fs_cmd_set_l2table_entry_silent(secondary, 0);
366 return err;
367}
368
369static void sd_cmd_unset_secondary(struct mlx5_core_dev *secondary)
370{
371 mlx5_fs_cmd_set_tx_flow_table_root(secondary, 0, true);
372 sd_secondary_destroy_alias_ft(secondary);
373 mlx5_fs_cmd_set_l2table_entry_silent(secondary, 0);
374}
375
4a04a31f
TT
376int mlx5_sd_init(struct mlx5_core_dev *dev)
377{
605fcce3 378 struct mlx5_core_dev *primary, *pos, *to;
a45af9a9 379 struct mlx5_sd *sd = mlx5_get_sd(dev);
605fcce3
TT
380 u8 alias_key[ACCESS_KEY_LEN];
381 int err, i;
63b9ce94
TT
382
383 err = sd_init(dev);
384 if (err)
385 return err;
386
a45af9a9
TT
387 sd = mlx5_get_sd(dev);
388 if (!sd)
389 return 0;
390
391 err = sd_register(dev);
392 if (err)
393 goto err_sd_cleanup;
394
605fcce3
TT
395 if (!mlx5_devcom_comp_is_ready(sd->devcom))
396 return 0;
397
398 primary = mlx5_sd_get_primary(dev);
399
400 for (i = 0; i < ACCESS_KEY_LEN; i++)
401 alias_key[i] = get_random_u8();
402
403 err = sd_cmd_set_primary(primary, alias_key);
404 if (err)
405 goto err_sd_unregister;
406
407 mlx5_sd_for_each_secondary(i, primary, pos) {
408 err = sd_cmd_set_secondary(pos, primary, alias_key);
409 if (err)
410 goto err_unset_secondaries;
411 }
412
4a04a31f 413 return 0;
a45af9a9 414
605fcce3
TT
415err_unset_secondaries:
416 to = pos;
417 mlx5_sd_for_each_secondary_to(i, primary, to, pos)
418 sd_cmd_unset_secondary(pos);
419 sd_cmd_unset_primary(primary);
420err_sd_unregister:
421 sd_unregister(dev);
a45af9a9
TT
422err_sd_cleanup:
423 sd_cleanup(dev);
424 return err;
4a04a31f
TT
425}
426
427void mlx5_sd_cleanup(struct mlx5_core_dev *dev)
428{
63b9ce94 429 struct mlx5_sd *sd = mlx5_get_sd(dev);
605fcce3
TT
430 struct mlx5_core_dev *primary, *pos;
431 int i;
63b9ce94
TT
432
433 if (!sd)
434 return;
435
605fcce3
TT
436 if (!mlx5_devcom_comp_is_ready(sd->devcom))
437 goto out;
438
439 primary = mlx5_sd_get_primary(dev);
440 mlx5_sd_for_each_secondary(i, primary, pos)
441 sd_cmd_unset_secondary(pos);
442 sd_cmd_unset_primary(primary);
443out:
a45af9a9 444 sd_unregister(dev);
63b9ce94 445 sd_cleanup(dev);
4a04a31f
TT
446}
447
448struct auxiliary_device *mlx5_sd_get_adev(struct mlx5_core_dev *dev,
449 struct auxiliary_device *adev,
450 int idx)
451{
a45af9a9
TT
452 struct mlx5_sd *sd = mlx5_get_sd(dev);
453 struct mlx5_core_dev *primary;
454
455 if (!sd)
456 return adev;
457
458 if (!mlx5_devcom_comp_is_ready(sd->devcom))
459 return NULL;
460
461 primary = mlx5_sd_get_primary(dev);
462 if (dev == primary)
463 return adev;
464
465 return &primary->priv.adev[idx]->adev;
4a04a31f 466}