1 /*
2 * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33 #include <linux/etherdevice.h>
34 #include <linux/idr.h>
35 #include <linux/mlx5/driver.h>
36 #include <linux/mlx5/mlx5_ifc.h>
37 #include <linux/mlx5/vport.h>
38 #include <linux/mlx5/fs.h>
39 #include "mlx5_core.h"
40 #include "eswitch.h"
41 #include "esw/indir_table.h"
42 #include "esw/acl/ofld.h"
43 #include "rdma.h"
44 #include "en.h"
45 #include "fs_core.h"
46 #include "lib/devcom.h"
47 #include "lib/eq.h"
48 #include "lib/fs_chains.h"
49 #include "en_tc.h"
50 #include "en/mapping.h"
51 #include "devlink.h"
52 #include "lag/lag.h"
53 #include "en/tc/post_meter.h"
54
55 #define mlx5_esw_for_each_rep(esw, i, rep) \
56 xa_for_each(&((esw)->offloads.vport_reps), i, rep)
57
58 #define mlx5_esw_for_each_sf_rep(esw, i, rep) \
59 xa_for_each_marked(&((esw)->offloads.vport_reps), i, rep, MLX5_ESW_VPT_SF)
60
61 #define mlx5_esw_for_each_vf_rep(esw, index, rep) \
62 mlx5_esw_for_each_entry_marked(&((esw)->offloads.vport_reps), index, \
63 rep, (esw)->esw_funcs.num_vfs, MLX5_ESW_VPT_VF)
64
65 /* There are two match-all miss flows, one for unicast dst mac and
66 * one for multicast.
67 */
68 #define MLX5_ESW_MISS_FLOWS (2)
69 #define UPLINK_REP_INDEX 0
70
71 #define MLX5_ESW_VPORT_TBL_SIZE 128
72 #define MLX5_ESW_VPORT_TBL_NUM_GROUPS 4
73
74 #define MLX5_ESW_FT_OFFLOADS_DROP_RULE (1)
75
76 static const struct esw_vport_tbl_namespace mlx5_esw_vport_tbl_mirror_ns = {
77 .max_fte = MLX5_ESW_VPORT_TBL_SIZE,
78 .max_num_groups = MLX5_ESW_VPORT_TBL_NUM_GROUPS,
79 .flags = 0,
80 };
81
mlx5_eswitch_get_rep(struct mlx5_eswitch * esw,u16 vport_num)82 static struct mlx5_eswitch_rep *mlx5_eswitch_get_rep(struct mlx5_eswitch *esw,
83 u16 vport_num)
84 {
85 return xa_load(&esw->offloads.vport_reps, vport_num);
86 }
87
88 static void
mlx5_eswitch_set_rule_flow_source(struct mlx5_eswitch * esw,struct mlx5_flow_spec * spec,struct mlx5_esw_flow_attr * attr)89 mlx5_eswitch_set_rule_flow_source(struct mlx5_eswitch *esw,
90 struct mlx5_flow_spec *spec,
91 struct mlx5_esw_flow_attr *attr)
92 {
93 if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) || !attr || !attr->in_rep)
94 return;
95
96 if (attr->int_port) {
97 spec->flow_context.flow_source = mlx5e_tc_int_port_get_flow_source(attr->int_port);
98
99 return;
100 }
101
102 spec->flow_context.flow_source = (attr->in_rep->vport == MLX5_VPORT_UPLINK) ?
103 MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK :
104 MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
105 }
106
107 /* Actually only the upper 16 bits of reg c0 need to be cleared, but the lower 16 bits
108 * are not needed as well in the following process. So clear them all for simplicity.
109 */
110 void
mlx5_eswitch_clear_rule_source_port(struct mlx5_eswitch * esw,struct mlx5_flow_spec * spec)111 mlx5_eswitch_clear_rule_source_port(struct mlx5_eswitch *esw, struct mlx5_flow_spec *spec)
112 {
113 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
114 void *misc2;
115
116 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
117 MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0, 0);
118
119 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
120 MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0, 0);
121
122 if (!memchr_inv(misc2, 0, MLX5_ST_SZ_BYTES(fte_match_set_misc2)))
123 spec->match_criteria_enable &= ~MLX5_MATCH_MISC_PARAMETERS_2;
124 }
125 }
126
127 static void
mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch * esw,struct mlx5_flow_spec * spec,struct mlx5_flow_attr * attr,struct mlx5_eswitch * src_esw,u16 vport)128 mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
129 struct mlx5_flow_spec *spec,
130 struct mlx5_flow_attr *attr,
131 struct mlx5_eswitch *src_esw,
132 u16 vport)
133 {
134 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
135 u32 metadata;
136 void *misc2;
137 void *misc;
138
139 /* Use metadata matching because vport is not represented by single
140 * VHCA in dual-port RoCE mode, and matching on source vport may fail.
141 */
142 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
143 if (mlx5_esw_indir_table_decap_vport(attr))
144 vport = mlx5_esw_indir_table_decap_vport(attr);
145
146 if (!attr->chain && esw_attr && esw_attr->int_port)
147 metadata =
148 mlx5e_tc_int_port_get_metadata_for_match(esw_attr->int_port);
149 else
150 metadata =
151 mlx5_eswitch_get_vport_metadata_for_match(src_esw, vport);
152
153 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
154 MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0, metadata);
155
156 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
157 MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
158 mlx5_eswitch_get_vport_metadata_mask());
159
160 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
161 } else {
162 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
163 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
164
165 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
166 MLX5_SET(fte_match_set_misc, misc,
167 source_eswitch_owner_vhca_id,
168 MLX5_CAP_GEN(src_esw->dev, vhca_id));
169
170 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
171 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
172 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
173 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
174 source_eswitch_owner_vhca_id);
175
176 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
177 }
178 }
179
180 static int
esw_setup_decap_indir(struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr)181 esw_setup_decap_indir(struct mlx5_eswitch *esw,
182 struct mlx5_flow_attr *attr)
183 {
184 struct mlx5_flow_table *ft;
185
186 if (!(attr->flags & MLX5_ATTR_FLAG_SRC_REWRITE))
187 return -EOPNOTSUPP;
188
189 ft = mlx5_esw_indir_table_get(esw, attr,
190 mlx5_esw_indir_table_decap_vport(attr), true);
191 return PTR_ERR_OR_ZERO(ft);
192 }
193
194 static void
esw_cleanup_decap_indir(struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr)195 esw_cleanup_decap_indir(struct mlx5_eswitch *esw,
196 struct mlx5_flow_attr *attr)
197 {
198 if (mlx5_esw_indir_table_decap_vport(attr))
199 mlx5_esw_indir_table_put(esw,
200 mlx5_esw_indir_table_decap_vport(attr),
201 true);
202 }
203
204 static int
esw_setup_mtu_dest(struct mlx5_flow_destination * dest,struct mlx5e_meter_attr * meter,int i)205 esw_setup_mtu_dest(struct mlx5_flow_destination *dest,
206 struct mlx5e_meter_attr *meter,
207 int i)
208 {
209 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_RANGE;
210 dest[i].range.field = MLX5_FLOW_DEST_RANGE_FIELD_PKT_LEN;
211 dest[i].range.min = 0;
212 dest[i].range.max = meter->params.mtu;
213 dest[i].range.hit_ft = mlx5e_post_meter_get_mtu_true_ft(meter->post_meter);
214 dest[i].range.miss_ft = mlx5e_post_meter_get_mtu_false_ft(meter->post_meter);
215
216 return 0;
217 }
218
219 static int
esw_setup_sampler_dest(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,u32 sampler_id,int i)220 esw_setup_sampler_dest(struct mlx5_flow_destination *dest,
221 struct mlx5_flow_act *flow_act,
222 u32 sampler_id,
223 int i)
224 {
225 flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
226 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER;
227 dest[i].sampler_id = sampler_id;
228
229 return 0;
230 }
231
232 static int
esw_setup_ft_dest(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr,int i)233 esw_setup_ft_dest(struct mlx5_flow_destination *dest,
234 struct mlx5_flow_act *flow_act,
235 struct mlx5_eswitch *esw,
236 struct mlx5_flow_attr *attr,
237 int i)
238 {
239 flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
240 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
241 dest[i].ft = attr->dest_ft;
242
243 if (mlx5_esw_indir_table_decap_vport(attr))
244 return esw_setup_decap_indir(esw, attr);
245 return 0;
246 }
247
248 static void
esw_setup_accept_dest(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_fs_chains * chains,int i)249 esw_setup_accept_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
250 struct mlx5_fs_chains *chains, int i)
251 {
252 if (mlx5_chains_ignore_flow_level_supported(chains))
253 flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
254 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
255 dest[i].ft = mlx5_chains_get_tc_end_ft(chains);
256 }
257
258 static void
esw_setup_slow_path_dest(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_eswitch * esw,int i)259 esw_setup_slow_path_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
260 struct mlx5_eswitch *esw, int i)
261 {
262 if (MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ignore_flow_level))
263 flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
264 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
265 dest[i].ft = mlx5_eswitch_get_slow_fdb(esw);
266 }
267
268 static int
esw_setup_chain_dest(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_fs_chains * chains,u32 chain,u32 prio,u32 level,int i)269 esw_setup_chain_dest(struct mlx5_flow_destination *dest,
270 struct mlx5_flow_act *flow_act,
271 struct mlx5_fs_chains *chains,
272 u32 chain, u32 prio, u32 level,
273 int i)
274 {
275 struct mlx5_flow_table *ft;
276
277 flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
278 ft = mlx5_chains_get_table(chains, chain, prio, level);
279 if (IS_ERR(ft))
280 return PTR_ERR(ft);
281
282 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
283 dest[i].ft = ft;
284 return 0;
285 }
286
esw_put_dest_tables_loop(struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr,int from,int to)287 static void esw_put_dest_tables_loop(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr,
288 int from, int to)
289 {
290 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
291 struct mlx5_fs_chains *chains = esw_chains(esw);
292 int i;
293
294 for (i = from; i < to; i++)
295 if (esw_attr->dests[i].flags & MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE)
296 mlx5_chains_put_table(chains, 0, 1, 0);
297 else if (mlx5_esw_indir_table_needed(esw, attr, esw_attr->dests[i].rep->vport,
298 esw_attr->dests[i].mdev))
299 mlx5_esw_indir_table_put(esw, esw_attr->dests[i].rep->vport,
300 false);
301 }
302
303 static bool
esw_is_chain_src_port_rewrite(struct mlx5_eswitch * esw,struct mlx5_esw_flow_attr * esw_attr)304 esw_is_chain_src_port_rewrite(struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr)
305 {
306 int i;
307
308 for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
309 if (esw_attr->dests[i].flags & MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE)
310 return true;
311 return false;
312 }
313
314 static int
esw_setup_chain_src_port_rewrite(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_eswitch * esw,struct mlx5_fs_chains * chains,struct mlx5_flow_attr * attr,int * i)315 esw_setup_chain_src_port_rewrite(struct mlx5_flow_destination *dest,
316 struct mlx5_flow_act *flow_act,
317 struct mlx5_eswitch *esw,
318 struct mlx5_fs_chains *chains,
319 struct mlx5_flow_attr *attr,
320 int *i)
321 {
322 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
323 int err;
324
325 if (!(attr->flags & MLX5_ATTR_FLAG_SRC_REWRITE))
326 return -EOPNOTSUPP;
327
328 /* flow steering cannot handle more than one dest with the same ft
329 * in a single flow
330 */
331 if (esw_attr->out_count - esw_attr->split_count > 1)
332 return -EOPNOTSUPP;
333
334 err = esw_setup_chain_dest(dest, flow_act, chains, attr->dest_chain, 1, 0, *i);
335 if (err)
336 return err;
337
338 if (esw_attr->dests[esw_attr->split_count].pkt_reformat) {
339 flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
340 flow_act->pkt_reformat = esw_attr->dests[esw_attr->split_count].pkt_reformat;
341 }
342 (*i)++;
343
344 return 0;
345 }
346
esw_cleanup_chain_src_port_rewrite(struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr)347 static void esw_cleanup_chain_src_port_rewrite(struct mlx5_eswitch *esw,
348 struct mlx5_flow_attr *attr)
349 {
350 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
351
352 esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, esw_attr->out_count);
353 }
354
355 static bool
esw_is_indir_table(struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr)356 esw_is_indir_table(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr)
357 {
358 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
359 bool result = false;
360 int i;
361
362 /* Indirect table is supported only for flows with in_port uplink
363 * and the destination is vport on the same eswitch as the uplink,
364 * return false in case at least one of destinations doesn't meet
365 * this criteria.
366 */
367 for (i = esw_attr->split_count; i < esw_attr->out_count; i++) {
368 if (esw_attr->dests[i].rep &&
369 mlx5_esw_indir_table_needed(esw, attr, esw_attr->dests[i].rep->vport,
370 esw_attr->dests[i].mdev)) {
371 result = true;
372 } else {
373 result = false;
374 break;
375 }
376 }
377 return result;
378 }
379
380 static int
esw_setup_indir_table(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr,bool ignore_flow_lvl,int * i)381 esw_setup_indir_table(struct mlx5_flow_destination *dest,
382 struct mlx5_flow_act *flow_act,
383 struct mlx5_eswitch *esw,
384 struct mlx5_flow_attr *attr,
385 bool ignore_flow_lvl,
386 int *i)
387 {
388 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
389 int j, err;
390
391 if (!(attr->flags & MLX5_ATTR_FLAG_SRC_REWRITE))
392 return -EOPNOTSUPP;
393
394 for (j = esw_attr->split_count; j < esw_attr->out_count; j++, (*i)++) {
395 if (ignore_flow_lvl)
396 flow_act->flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
397 dest[*i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
398
399 dest[*i].ft = mlx5_esw_indir_table_get(esw, attr,
400 esw_attr->dests[j].rep->vport, false);
401 if (IS_ERR(dest[*i].ft)) {
402 err = PTR_ERR(dest[*i].ft);
403 goto err_indir_tbl_get;
404 }
405 }
406
407 if (mlx5_esw_indir_table_decap_vport(attr)) {
408 err = esw_setup_decap_indir(esw, attr);
409 if (err)
410 goto err_indir_tbl_get;
411 }
412
413 return 0;
414
415 err_indir_tbl_get:
416 esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, j);
417 return err;
418 }
419
esw_cleanup_indir_table(struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr)420 static void esw_cleanup_indir_table(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr)
421 {
422 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
423
424 esw_put_dest_tables_loop(esw, attr, esw_attr->split_count, esw_attr->out_count);
425 esw_cleanup_decap_indir(esw, attr);
426 }
427
428 static void
esw_cleanup_chain_dest(struct mlx5_fs_chains * chains,u32 chain,u32 prio,u32 level)429 esw_cleanup_chain_dest(struct mlx5_fs_chains *chains, u32 chain, u32 prio, u32 level)
430 {
431 mlx5_chains_put_table(chains, chain, prio, level);
432 }
433
434 static void
esw_setup_vport_dest(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_eswitch * esw,struct mlx5_esw_flow_attr * esw_attr,int attr_idx,int dest_idx,bool pkt_reformat)435 esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
436 struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
437 int attr_idx, int dest_idx, bool pkt_reformat)
438 {
439 dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
440 dest[dest_idx].vport.num = esw_attr->dests[attr_idx].rep->vport;
441 if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
442 dest[dest_idx].vport.vhca_id =
443 MLX5_CAP_GEN(esw_attr->dests[attr_idx].mdev, vhca_id);
444 dest[dest_idx].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
445 if (dest[dest_idx].vport.num == MLX5_VPORT_UPLINK &&
446 mlx5_lag_is_mpesw(esw->dev))
447 dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_UPLINK;
448 }
449 if (esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) {
450 if (pkt_reformat) {
451 flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
452 flow_act->pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
453 }
454 dest[dest_idx].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
455 dest[dest_idx].vport.pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
456 }
457 }
458
459 static int
esw_setup_vport_dests(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_eswitch * esw,struct mlx5_esw_flow_attr * esw_attr,int i)460 esw_setup_vport_dests(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
461 struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
462 int i)
463 {
464 int j;
465
466 for (j = esw_attr->split_count; j < esw_attr->out_count; j++, i++)
467 esw_setup_vport_dest(dest, flow_act, esw, esw_attr, j, i, true);
468 return i;
469 }
470
471 static bool
esw_src_port_rewrite_supported(struct mlx5_eswitch * esw)472 esw_src_port_rewrite_supported(struct mlx5_eswitch *esw)
473 {
474 return MLX5_CAP_GEN(esw->dev, reg_c_preserve) &&
475 mlx5_eswitch_vport_match_metadata_enabled(esw) &&
476 MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ignore_flow_level);
477 }
478
479 static int
esw_setup_dests(struct mlx5_flow_destination * dest,struct mlx5_flow_act * flow_act,struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr,struct mlx5_flow_spec * spec,int * i)480 esw_setup_dests(struct mlx5_flow_destination *dest,
481 struct mlx5_flow_act *flow_act,
482 struct mlx5_eswitch *esw,
483 struct mlx5_flow_attr *attr,
484 struct mlx5_flow_spec *spec,
485 int *i)
486 {
487 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
488 struct mlx5_fs_chains *chains = esw_chains(esw);
489 int err = 0;
490
491 if (!mlx5_eswitch_termtbl_required(esw, attr, flow_act, spec) &&
492 esw_src_port_rewrite_supported(esw))
493 attr->flags |= MLX5_ATTR_FLAG_SRC_REWRITE;
494
495 if (attr->flags & MLX5_ATTR_FLAG_SLOW_PATH) {
496 esw_setup_slow_path_dest(dest, flow_act, esw, *i);
497 (*i)++;
498 goto out;
499 }
500
501 if (attr->flags & MLX5_ATTR_FLAG_SAMPLE) {
502 esw_setup_sampler_dest(dest, flow_act, attr->sample_attr.sampler_id, *i);
503 (*i)++;
504 } else if (attr->flags & MLX5_ATTR_FLAG_ACCEPT) {
505 esw_setup_accept_dest(dest, flow_act, chains, *i);
506 (*i)++;
507 } else if (attr->flags & MLX5_ATTR_FLAG_MTU) {
508 err = esw_setup_mtu_dest(dest, &attr->meter_attr, *i);
509 (*i)++;
510 } else if (esw_is_indir_table(esw, attr)) {
511 err = esw_setup_indir_table(dest, flow_act, esw, attr, true, i);
512 } else if (esw_is_chain_src_port_rewrite(esw, esw_attr)) {
513 err = esw_setup_chain_src_port_rewrite(dest, flow_act, esw, chains, attr, i);
514 } else {
515 *i = esw_setup_vport_dests(dest, flow_act, esw, esw_attr, *i);
516
517 if (attr->dest_ft) {
518 err = esw_setup_ft_dest(dest, flow_act, esw, attr, *i);
519 (*i)++;
520 } else if (attr->dest_chain) {
521 err = esw_setup_chain_dest(dest, flow_act, chains, attr->dest_chain,
522 1, 0, *i);
523 (*i)++;
524 }
525 }
526
527 out:
528 return err;
529 }
530
531 static void
esw_cleanup_dests(struct mlx5_eswitch * esw,struct mlx5_flow_attr * attr)532 esw_cleanup_dests(struct mlx5_eswitch *esw,
533 struct mlx5_flow_attr *attr)
534 {
535 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
536 struct mlx5_fs_chains *chains = esw_chains(esw);
537
538 if (attr->dest_ft) {
539 esw_cleanup_decap_indir(esw, attr);
540 } else if (!mlx5e_tc_attr_flags_skip(attr->flags)) {
541 if (attr->dest_chain)
542 esw_cleanup_chain_dest(chains, attr->dest_chain, 1, 0);
543 else if (esw_is_indir_table(esw, attr))
544 esw_cleanup_indir_table(esw, attr);
545 else if (esw_is_chain_src_port_rewrite(esw, esw_attr))
546 esw_cleanup_chain_src_port_rewrite(esw, attr);
547 }
548 }
549
550 static void
esw_setup_meter(struct mlx5_flow_attr * attr,struct mlx5_flow_act * flow_act)551 esw_setup_meter(struct mlx5_flow_attr *attr, struct mlx5_flow_act *flow_act)
552 {
553 struct mlx5e_flow_meter_handle *meter;
554
555 meter = attr->meter_attr.meter;
556 flow_act->exe_aso.type = attr->exe_aso_type;
557 flow_act->exe_aso.object_id = meter->obj_id;
558 flow_act->exe_aso.flow_meter.meter_idx = meter->idx;
559 flow_act->exe_aso.flow_meter.init_color = MLX5_FLOW_METER_COLOR_GREEN;
560 /* use metadata reg 5 for packet color */
561 flow_act->exe_aso.return_reg_id = 5;
562 }
563
564 struct mlx5_flow_handle *
mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch * esw,struct mlx5_flow_spec * spec,struct mlx5_flow_attr * attr)565 mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
566 struct mlx5_flow_spec *spec,
567 struct mlx5_flow_attr *attr)
568 {
569 struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
570 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
571 struct mlx5_fs_chains *chains = esw_chains(esw);
572 bool split = !!(esw_attr->split_count);
573 struct mlx5_vport_tbl_attr fwd_attr;
574 struct mlx5_flow_destination *dest;
575 struct mlx5_flow_handle *rule;
576 struct mlx5_flow_table *fdb;
577 int i = 0;
578
579 if (esw->mode != MLX5_ESWITCH_OFFLOADS)
580 return ERR_PTR(-EOPNOTSUPP);
581
582 if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
583 return ERR_PTR(-EOPNOTSUPP);
584
585 dest = kcalloc(MLX5_MAX_FLOW_FWD_VPORTS + 1, sizeof(*dest), GFP_KERNEL);
586 if (!dest)
587 return ERR_PTR(-ENOMEM);
588
589 flow_act.action = attr->action;
590
591 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
592 flow_act.vlan[0].ethtype = ntohs(esw_attr->vlan_proto[0]);
593 flow_act.vlan[0].vid = esw_attr->vlan_vid[0];
594 flow_act.vlan[0].prio = esw_attr->vlan_prio[0];
595 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
596 flow_act.vlan[1].ethtype = ntohs(esw_attr->vlan_proto[1]);
597 flow_act.vlan[1].vid = esw_attr->vlan_vid[1];
598 flow_act.vlan[1].prio = esw_attr->vlan_prio[1];
599 }
600 }
601
602 mlx5_eswitch_set_rule_flow_source(esw, spec, esw_attr);
603
604 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
605 int err;
606
607 err = esw_setup_dests(dest, &flow_act, esw, attr, spec, &i);
608 if (err) {
609 rule = ERR_PTR(err);
610 goto err_create_goto_table;
611 }
612 }
613
614 if (esw_attr->decap_pkt_reformat)
615 flow_act.pkt_reformat = esw_attr->decap_pkt_reformat;
616
617 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
618 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
619 dest[i].counter_id = mlx5_fc_id(attr->counter);
620 i++;
621 }
622
623 if (attr->outer_match_level != MLX5_MATCH_NONE)
624 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
625 if (attr->inner_match_level != MLX5_MATCH_NONE)
626 spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
627
628 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
629 flow_act.modify_hdr = attr->modify_hdr;
630
631 if ((flow_act.action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) &&
632 attr->exe_aso_type == MLX5_EXE_ASO_FLOW_METER)
633 esw_setup_meter(attr, &flow_act);
634
635 if (split) {
636 fwd_attr.chain = attr->chain;
637 fwd_attr.prio = attr->prio;
638 fwd_attr.vport = esw_attr->in_rep->vport;
639 fwd_attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
640
641 fdb = mlx5_esw_vporttbl_get(esw, &fwd_attr);
642 } else {
643 if (attr->chain || attr->prio)
644 fdb = mlx5_chains_get_table(chains, attr->chain,
645 attr->prio, 0);
646 else
647 fdb = attr->ft;
648
649 if (!(attr->flags & MLX5_ATTR_FLAG_NO_IN_PORT))
650 mlx5_eswitch_set_rule_source_port(esw, spec, attr,
651 esw_attr->in_mdev->priv.eswitch,
652 esw_attr->in_rep->vport);
653 }
654 if (IS_ERR(fdb)) {
655 rule = ERR_CAST(fdb);
656 goto err_esw_get;
657 }
658
659 if (!i) {
660 kfree(dest);
661 dest = NULL;
662 }
663
664 if (mlx5_eswitch_termtbl_required(esw, attr, &flow_act, spec))
665 rule = mlx5_eswitch_add_termtbl_rule(esw, fdb, spec, esw_attr,
666 &flow_act, dest, i);
667 else
668 rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
669 if (IS_ERR(rule))
670 goto err_add_rule;
671 else
672 atomic64_inc(&esw->offloads.num_flows);
673
674 kfree(dest);
675 return rule;
676
677 err_add_rule:
678 if (split)
679 mlx5_esw_vporttbl_put(esw, &fwd_attr);
680 else if (attr->chain || attr->prio)
681 mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
682 err_esw_get:
683 esw_cleanup_dests(esw, attr);
684 err_create_goto_table:
685 kfree(dest);
686 return rule;
687 }
688
689 struct mlx5_flow_handle *
mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch * esw,struct mlx5_flow_spec * spec,struct mlx5_flow_attr * attr)690 mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
691 struct mlx5_flow_spec *spec,
692 struct mlx5_flow_attr *attr)
693 {
694 struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
695 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
696 struct mlx5_fs_chains *chains = esw_chains(esw);
697 struct mlx5_vport_tbl_attr fwd_attr;
698 struct mlx5_flow_destination *dest;
699 struct mlx5_flow_table *fast_fdb;
700 struct mlx5_flow_table *fwd_fdb;
701 struct mlx5_flow_handle *rule;
702 int i, err = 0;
703
704 dest = kcalloc(MLX5_MAX_FLOW_FWD_VPORTS + 1, sizeof(*dest), GFP_KERNEL);
705 if (!dest)
706 return ERR_PTR(-ENOMEM);
707
708 fast_fdb = mlx5_chains_get_table(chains, attr->chain, attr->prio, 0);
709 if (IS_ERR(fast_fdb)) {
710 rule = ERR_CAST(fast_fdb);
711 goto err_get_fast;
712 }
713
714 fwd_attr.chain = attr->chain;
715 fwd_attr.prio = attr->prio;
716 fwd_attr.vport = esw_attr->in_rep->vport;
717 fwd_attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
718 fwd_fdb = mlx5_esw_vporttbl_get(esw, &fwd_attr);
719 if (IS_ERR(fwd_fdb)) {
720 rule = ERR_CAST(fwd_fdb);
721 goto err_get_fwd;
722 }
723
724 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
725 for (i = 0; i < esw_attr->split_count; i++) {
726 if (esw_is_indir_table(esw, attr))
727 err = esw_setup_indir_table(dest, &flow_act, esw, attr, false, &i);
728 else if (esw_is_chain_src_port_rewrite(esw, esw_attr))
729 err = esw_setup_chain_src_port_rewrite(dest, &flow_act, esw, chains, attr,
730 &i);
731 else
732 esw_setup_vport_dest(dest, &flow_act, esw, esw_attr, i, i, false);
733
734 if (err) {
735 rule = ERR_PTR(err);
736 goto err_chain_src_rewrite;
737 }
738 }
739 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
740 dest[i].ft = fwd_fdb;
741 i++;
742
743 mlx5_eswitch_set_rule_source_port(esw, spec, attr,
744 esw_attr->in_mdev->priv.eswitch,
745 esw_attr->in_rep->vport);
746
747 if (attr->outer_match_level != MLX5_MATCH_NONE)
748 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
749
750 flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
751 rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
752
753 if (IS_ERR(rule)) {
754 i = esw_attr->split_count;
755 goto err_chain_src_rewrite;
756 }
757
758 atomic64_inc(&esw->offloads.num_flows);
759
760 kfree(dest);
761 return rule;
762 err_chain_src_rewrite:
763 esw_put_dest_tables_loop(esw, attr, 0, i);
764 mlx5_esw_vporttbl_put(esw, &fwd_attr);
765 err_get_fwd:
766 mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
767 err_get_fast:
768 kfree(dest);
769 return rule;
770 }
771
772 static void
__mlx5_eswitch_del_rule(struct mlx5_eswitch * esw,struct mlx5_flow_handle * rule,struct mlx5_flow_attr * attr,bool fwd_rule)773 __mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
774 struct mlx5_flow_handle *rule,
775 struct mlx5_flow_attr *attr,
776 bool fwd_rule)
777 {
778 struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
779 struct mlx5_fs_chains *chains = esw_chains(esw);
780 bool split = (esw_attr->split_count > 0);
781 struct mlx5_vport_tbl_attr fwd_attr;
782 int i;
783
784 mlx5_del_flow_rules(rule);
785
786 if (!mlx5e_tc_attr_flags_skip(attr->flags)) {
787 /* unref the term table */
788 for (i = 0; i < MLX5_MAX_FLOW_FWD_VPORTS; i++) {
789 if (esw_attr->dests[i].termtbl)
790 mlx5_eswitch_termtbl_put(esw, esw_attr->dests[i].termtbl);
791 }
792 }
793
794 atomic64_dec(&esw->offloads.num_flows);
795
796 if (fwd_rule || split) {
797 fwd_attr.chain = attr->chain;
798 fwd_attr.prio = attr->prio;
799 fwd_attr.vport = esw_attr->in_rep->vport;
800 fwd_attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
801 }
802
803 if (fwd_rule) {
804 mlx5_esw_vporttbl_put(esw, &fwd_attr);
805 mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
806 esw_put_dest_tables_loop(esw, attr, 0, esw_attr->split_count);
807 } else {
808 if (split)
809 mlx5_esw_vporttbl_put(esw, &fwd_attr);
810 else if (attr->chain || attr->prio)
811 mlx5_chains_put_table(chains, attr->chain, attr->prio, 0);
812 esw_cleanup_dests(esw, attr);
813 }
814 }
815
816 void
mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch * esw,struct mlx5_flow_handle * rule,struct mlx5_flow_attr * attr)817 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
818 struct mlx5_flow_handle *rule,
819 struct mlx5_flow_attr *attr)
820 {
821 __mlx5_eswitch_del_rule(esw, rule, attr, false);
822 }
823
824 void
mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch * esw,struct mlx5_flow_handle * rule,struct mlx5_flow_attr * attr)825 mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
826 struct mlx5_flow_handle *rule,
827 struct mlx5_flow_attr *attr)
828 {
829 __mlx5_eswitch_del_rule(esw, rule, attr, true);
830 }
831
832 struct mlx5_flow_handle *
mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch * on_esw,struct mlx5_eswitch * from_esw,struct mlx5_eswitch_rep * rep,u32 sqn)833 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw,
834 struct mlx5_eswitch *from_esw,
835 struct mlx5_eswitch_rep *rep,
836 u32 sqn)
837 {
838 struct mlx5_flow_act flow_act = {0};
839 struct mlx5_flow_destination dest = {};
840 struct mlx5_flow_handle *flow_rule;
841 struct mlx5_flow_spec *spec;
842 void *misc;
843
844 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
845 if (!spec) {
846 flow_rule = ERR_PTR(-ENOMEM);
847 goto out;
848 }
849
850 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
851 MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
852 /* source vport is the esw manager */
853 MLX5_SET(fte_match_set_misc, misc, source_port, from_esw->manager_vport);
854 if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch))
855 MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
856 MLX5_CAP_GEN(from_esw->dev, vhca_id));
857
858 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
859 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
860 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
861 if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch))
862 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
863 source_eswitch_owner_vhca_id);
864
865 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
866 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
867 dest.vport.num = rep->vport;
868 dest.vport.vhca_id = MLX5_CAP_GEN(rep->esw->dev, vhca_id);
869 dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
870 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
871
872 if (MLX5_CAP_ESW_FLOWTABLE(on_esw->dev, flow_source) &&
873 rep->vport == MLX5_VPORT_UPLINK)
874 spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
875
876 flow_rule = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(on_esw),
877 spec, &flow_act, &dest, 1);
878 if (IS_ERR(flow_rule))
879 esw_warn(on_esw->dev, "FDB: Failed to add send to vport rule err %ld\n",
880 PTR_ERR(flow_rule));
881 out:
882 kvfree(spec);
883 return flow_rule;
884 }
885 EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
886
mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle * rule)887 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
888 {
889 mlx5_del_flow_rules(rule);
890 }
891
mlx5_eswitch_del_send_to_vport_meta_rule(struct mlx5_flow_handle * rule)892 void mlx5_eswitch_del_send_to_vport_meta_rule(struct mlx5_flow_handle *rule)
893 {
894 if (rule)
895 mlx5_del_flow_rules(rule);
896 }
897
898 struct mlx5_flow_handle *
mlx5_eswitch_add_send_to_vport_meta_rule(struct mlx5_eswitch * esw,u16 vport_num)899 mlx5_eswitch_add_send_to_vport_meta_rule(struct mlx5_eswitch *esw, u16 vport_num)
900 {
901 struct mlx5_flow_destination dest = {};
902 struct mlx5_flow_act flow_act = {0};
903 struct mlx5_flow_handle *flow_rule;
904 struct mlx5_flow_spec *spec;
905
906 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
907 if (!spec)
908 return ERR_PTR(-ENOMEM);
909
910 MLX5_SET(fte_match_param, spec->match_criteria,
911 misc_parameters_2.metadata_reg_c_0, mlx5_eswitch_get_vport_metadata_mask());
912 MLX5_SET(fte_match_param, spec->match_criteria,
913 misc_parameters_2.metadata_reg_c_1, ESW_TUN_MASK);
914 MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_1,
915 ESW_TUN_SLOW_TABLE_GOTO_VPORT_MARK);
916
917 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
918 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
919 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
920
921 MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_0,
922 mlx5_eswitch_get_vport_metadata_for_match(esw, vport_num));
923 dest.vport.num = vport_num;
924
925 flow_rule = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
926 spec, &flow_act, &dest, 1);
927 if (IS_ERR(flow_rule))
928 esw_warn(esw->dev, "FDB: Failed to add send to vport meta rule vport %d, err %ld\n",
929 vport_num, PTR_ERR(flow_rule));
930
931 kvfree(spec);
932 return flow_rule;
933 }
934
mlx5_eswitch_reg_c1_loopback_supported(struct mlx5_eswitch * esw)935 static bool mlx5_eswitch_reg_c1_loopback_supported(struct mlx5_eswitch *esw)
936 {
937 return MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
938 MLX5_FDB_TO_VPORT_REG_C_1;
939 }
940
esw_set_passing_vport_metadata(struct mlx5_eswitch * esw,bool enable)941 static int esw_set_passing_vport_metadata(struct mlx5_eswitch *esw, bool enable)
942 {
943 u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
944 u32 min[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
945 u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {};
946 u8 curr, wanted;
947 int err;
948
949 if (!mlx5_eswitch_reg_c1_loopback_supported(esw) &&
950 !mlx5_eswitch_vport_match_metadata_enabled(esw))
951 return 0;
952
953 MLX5_SET(query_esw_vport_context_in, in, opcode,
954 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
955 err = mlx5_cmd_exec_inout(esw->dev, query_esw_vport_context, in, out);
956 if (err)
957 return err;
958
959 curr = MLX5_GET(query_esw_vport_context_out, out,
960 esw_vport_context.fdb_to_vport_reg_c_id);
961 wanted = MLX5_FDB_TO_VPORT_REG_C_0;
962 if (mlx5_eswitch_reg_c1_loopback_supported(esw))
963 wanted |= MLX5_FDB_TO_VPORT_REG_C_1;
964
965 if (enable)
966 curr |= wanted;
967 else
968 curr &= ~wanted;
969
970 MLX5_SET(modify_esw_vport_context_in, min,
971 esw_vport_context.fdb_to_vport_reg_c_id, curr);
972 MLX5_SET(modify_esw_vport_context_in, min,
973 field_select.fdb_to_vport_reg_c_id, 1);
974
975 err = mlx5_eswitch_modify_esw_vport_context(esw->dev, 0, false, min);
976 if (!err) {
977 if (enable && (curr & MLX5_FDB_TO_VPORT_REG_C_1))
978 esw->flags |= MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED;
979 else
980 esw->flags &= ~MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED;
981 }
982
983 return err;
984 }
985
peer_miss_rules_setup(struct mlx5_eswitch * esw,struct mlx5_core_dev * peer_dev,struct mlx5_flow_spec * spec,struct mlx5_flow_destination * dest)986 static void peer_miss_rules_setup(struct mlx5_eswitch *esw,
987 struct mlx5_core_dev *peer_dev,
988 struct mlx5_flow_spec *spec,
989 struct mlx5_flow_destination *dest)
990 {
991 void *misc;
992
993 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
994 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
995 misc_parameters_2);
996 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
997 mlx5_eswitch_get_vport_metadata_mask());
998
999 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1000 } else {
1001 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1002 misc_parameters);
1003
1004 MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
1005 MLX5_CAP_GEN(peer_dev, vhca_id));
1006
1007 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
1008
1009 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1010 misc_parameters);
1011 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1012 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
1013 source_eswitch_owner_vhca_id);
1014 }
1015
1016 dest->type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
1017 dest->vport.num = peer_dev->priv.eswitch->manager_vport;
1018 dest->vport.vhca_id = MLX5_CAP_GEN(peer_dev, vhca_id);
1019 dest->vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
1020 }
1021
esw_set_peer_miss_rule_source_port(struct mlx5_eswitch * esw,struct mlx5_eswitch * peer_esw,struct mlx5_flow_spec * spec,u16 vport)1022 static void esw_set_peer_miss_rule_source_port(struct mlx5_eswitch *esw,
1023 struct mlx5_eswitch *peer_esw,
1024 struct mlx5_flow_spec *spec,
1025 u16 vport)
1026 {
1027 void *misc;
1028
1029 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1030 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1031 misc_parameters_2);
1032 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1033 mlx5_eswitch_get_vport_metadata_for_match(peer_esw,
1034 vport));
1035 } else {
1036 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1037 misc_parameters);
1038 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
1039 }
1040 }
1041
esw_add_fdb_peer_miss_rules(struct mlx5_eswitch * esw,struct mlx5_core_dev * peer_dev)1042 static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
1043 struct mlx5_core_dev *peer_dev)
1044 {
1045 struct mlx5_flow_destination dest = {};
1046 struct mlx5_flow_act flow_act = {0};
1047 struct mlx5_flow_handle **flows;
1048 /* total vports is the same for both e-switches */
1049 int nvports = esw->total_vports;
1050 struct mlx5_flow_handle *flow;
1051 struct mlx5_flow_spec *spec;
1052 struct mlx5_vport *vport;
1053 unsigned long i;
1054 void *misc;
1055 int err;
1056
1057 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1058 if (!spec)
1059 return -ENOMEM;
1060
1061 peer_miss_rules_setup(esw, peer_dev, spec, &dest);
1062
1063 flows = kvcalloc(nvports, sizeof(*flows), GFP_KERNEL);
1064 if (!flows) {
1065 err = -ENOMEM;
1066 goto alloc_flows_err;
1067 }
1068
1069 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1070 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1071 misc_parameters);
1072
1073 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1074 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1075 esw_set_peer_miss_rule_source_port(esw, peer_dev->priv.eswitch,
1076 spec, MLX5_VPORT_PF);
1077
1078 flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
1079 spec, &flow_act, &dest, 1);
1080 if (IS_ERR(flow)) {
1081 err = PTR_ERR(flow);
1082 goto add_pf_flow_err;
1083 }
1084 flows[vport->index] = flow;
1085 }
1086
1087 if (mlx5_ecpf_vport_exists(esw->dev)) {
1088 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1089 MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_ECPF);
1090 flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
1091 spec, &flow_act, &dest, 1);
1092 if (IS_ERR(flow)) {
1093 err = PTR_ERR(flow);
1094 goto add_ecpf_flow_err;
1095 }
1096 flows[vport->index] = flow;
1097 }
1098
1099 mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev)) {
1100 esw_set_peer_miss_rule_source_port(esw,
1101 peer_dev->priv.eswitch,
1102 spec, vport->vport);
1103
1104 flow = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
1105 spec, &flow_act, &dest, 1);
1106 if (IS_ERR(flow)) {
1107 err = PTR_ERR(flow);
1108 goto add_vf_flow_err;
1109 }
1110 flows[vport->index] = flow;
1111 }
1112
1113 esw->fdb_table.offloads.peer_miss_rules = flows;
1114
1115 kvfree(spec);
1116 return 0;
1117
1118 add_vf_flow_err:
1119 mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev)) {
1120 if (!flows[vport->index])
1121 continue;
1122 mlx5_del_flow_rules(flows[vport->index]);
1123 }
1124 if (mlx5_ecpf_vport_exists(esw->dev)) {
1125 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1126 mlx5_del_flow_rules(flows[vport->index]);
1127 }
1128 add_ecpf_flow_err:
1129 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1130 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1131 mlx5_del_flow_rules(flows[vport->index]);
1132 }
1133 add_pf_flow_err:
1134 esw_warn(esw->dev, "FDB: Failed to add peer miss flow rule err %d\n", err);
1135 kvfree(flows);
1136 alloc_flows_err:
1137 kvfree(spec);
1138 return err;
1139 }
1140
esw_del_fdb_peer_miss_rules(struct mlx5_eswitch * esw)1141 static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw)
1142 {
1143 struct mlx5_flow_handle **flows;
1144 struct mlx5_vport *vport;
1145 unsigned long i;
1146
1147 flows = esw->fdb_table.offloads.peer_miss_rules;
1148
1149 mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev))
1150 mlx5_del_flow_rules(flows[vport->index]);
1151
1152 if (mlx5_ecpf_vport_exists(esw->dev)) {
1153 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1154 mlx5_del_flow_rules(flows[vport->index]);
1155 }
1156
1157 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1158 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1159 mlx5_del_flow_rules(flows[vport->index]);
1160 }
1161 kvfree(flows);
1162 }
1163
esw_add_fdb_miss_rule(struct mlx5_eswitch * esw)1164 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
1165 {
1166 struct mlx5_flow_act flow_act = {0};
1167 struct mlx5_flow_destination dest = {};
1168 struct mlx5_flow_handle *flow_rule = NULL;
1169 struct mlx5_flow_spec *spec;
1170 void *headers_c;
1171 void *headers_v;
1172 int err = 0;
1173 u8 *dmac_c;
1174 u8 *dmac_v;
1175
1176 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1177 if (!spec) {
1178 err = -ENOMEM;
1179 goto out;
1180 }
1181
1182 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1183 headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1184 outer_headers);
1185 dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
1186 outer_headers.dmac_47_16);
1187 dmac_c[0] = 0x01;
1188
1189 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
1190 dest.vport.num = esw->manager_vport;
1191 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1192
1193 flow_rule = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
1194 spec, &flow_act, &dest, 1);
1195 if (IS_ERR(flow_rule)) {
1196 err = PTR_ERR(flow_rule);
1197 esw_warn(esw->dev, "FDB: Failed to add unicast miss flow rule err %d\n", err);
1198 goto out;
1199 }
1200
1201 esw->fdb_table.offloads.miss_rule_uni = flow_rule;
1202
1203 headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1204 outer_headers);
1205 dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
1206 outer_headers.dmac_47_16);
1207 dmac_v[0] = 0x01;
1208 flow_rule = mlx5_add_flow_rules(mlx5_eswitch_get_slow_fdb(esw),
1209 spec, &flow_act, &dest, 1);
1210 if (IS_ERR(flow_rule)) {
1211 err = PTR_ERR(flow_rule);
1212 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
1213 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
1214 goto out;
1215 }
1216
1217 esw->fdb_table.offloads.miss_rule_multi = flow_rule;
1218
1219 out:
1220 kvfree(spec);
1221 return err;
1222 }
1223
1224 struct mlx5_flow_handle *
esw_add_restore_rule(struct mlx5_eswitch * esw,u32 tag)1225 esw_add_restore_rule(struct mlx5_eswitch *esw, u32 tag)
1226 {
1227 struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
1228 struct mlx5_flow_table *ft = esw->offloads.ft_offloads_restore;
1229 struct mlx5_flow_context *flow_context;
1230 struct mlx5_flow_handle *flow_rule;
1231 struct mlx5_flow_destination dest;
1232 struct mlx5_flow_spec *spec;
1233 void *misc;
1234
1235 if (!mlx5_eswitch_reg_c1_loopback_supported(esw))
1236 return ERR_PTR(-EOPNOTSUPP);
1237
1238 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1239 if (!spec)
1240 return ERR_PTR(-ENOMEM);
1241
1242 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
1243 misc_parameters_2);
1244 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1245 ESW_REG_C0_USER_DATA_METADATA_MASK);
1246 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
1247 misc_parameters_2);
1248 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0, tag);
1249 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1250 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
1251 MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1252 flow_act.modify_hdr = esw->offloads.restore_copy_hdr_id;
1253
1254 flow_context = &spec->flow_context;
1255 flow_context->flags |= FLOW_CONTEXT_HAS_TAG;
1256 flow_context->flow_tag = tag;
1257 dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
1258 dest.ft = esw->offloads.ft_offloads;
1259
1260 flow_rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
1261 kvfree(spec);
1262
1263 if (IS_ERR(flow_rule))
1264 esw_warn(esw->dev,
1265 "Failed to create restore rule for tag: %d, err(%d)\n",
1266 tag, (int)PTR_ERR(flow_rule));
1267
1268 return flow_rule;
1269 }
1270
1271 #define MAX_PF_SQ 256
1272 #define MAX_SQ_NVPORTS 32
1273
esw_set_flow_group_source_port(struct mlx5_eswitch * esw,u32 * flow_group_in)1274 static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw,
1275 u32 *flow_group_in)
1276 {
1277 void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1278 flow_group_in,
1279 match_criteria);
1280
1281 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1282 MLX5_SET(create_flow_group_in, flow_group_in,
1283 match_criteria_enable,
1284 MLX5_MATCH_MISC_PARAMETERS_2);
1285
1286 MLX5_SET(fte_match_param, match_criteria,
1287 misc_parameters_2.metadata_reg_c_0,
1288 mlx5_eswitch_get_vport_metadata_mask());
1289 } else {
1290 MLX5_SET(create_flow_group_in, flow_group_in,
1291 match_criteria_enable,
1292 MLX5_MATCH_MISC_PARAMETERS);
1293
1294 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1295 misc_parameters.source_port);
1296 }
1297 }
1298
1299 #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
esw_vport_tbl_put(struct mlx5_eswitch * esw)1300 static void esw_vport_tbl_put(struct mlx5_eswitch *esw)
1301 {
1302 struct mlx5_vport_tbl_attr attr;
1303 struct mlx5_vport *vport;
1304 unsigned long i;
1305
1306 attr.chain = 0;
1307 attr.prio = 1;
1308 mlx5_esw_for_each_vport(esw, i, vport) {
1309 attr.vport = vport->vport;
1310 attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
1311 mlx5_esw_vporttbl_put(esw, &attr);
1312 }
1313 }
1314
esw_vport_tbl_get(struct mlx5_eswitch * esw)1315 static int esw_vport_tbl_get(struct mlx5_eswitch *esw)
1316 {
1317 struct mlx5_vport_tbl_attr attr;
1318 struct mlx5_flow_table *fdb;
1319 struct mlx5_vport *vport;
1320 unsigned long i;
1321
1322 attr.chain = 0;
1323 attr.prio = 1;
1324 mlx5_esw_for_each_vport(esw, i, vport) {
1325 attr.vport = vport->vport;
1326 attr.vport_ns = &mlx5_esw_vport_tbl_mirror_ns;
1327 fdb = mlx5_esw_vporttbl_get(esw, &attr);
1328 if (IS_ERR(fdb))
1329 goto out;
1330 }
1331 return 0;
1332
1333 out:
1334 esw_vport_tbl_put(esw);
1335 return PTR_ERR(fdb);
1336 }
1337
1338 #define fdb_modify_header_fwd_to_table_supported(esw) \
1339 (MLX5_CAP_ESW_FLOWTABLE((esw)->dev, fdb_modify_header_fwd_to_table))
esw_init_chains_offload_flags(struct mlx5_eswitch * esw,u32 * flags)1340 static void esw_init_chains_offload_flags(struct mlx5_eswitch *esw, u32 *flags)
1341 {
1342 struct mlx5_core_dev *dev = esw->dev;
1343
1344 if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, ignore_flow_level))
1345 *flags |= MLX5_CHAINS_IGNORE_FLOW_LEVEL_SUPPORTED;
1346
1347 if (!MLX5_CAP_ESW_FLOWTABLE(dev, multi_fdb_encap) &&
1348 esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
1349 *flags &= ~MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1350 esw_warn(dev, "Tc chains and priorities offload aren't supported, update firmware if needed\n");
1351 } else if (!mlx5_eswitch_reg_c1_loopback_enabled(esw)) {
1352 *flags &= ~MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1353 esw_warn(dev, "Tc chains and priorities offload aren't supported\n");
1354 } else if (!fdb_modify_header_fwd_to_table_supported(esw)) {
1355 /* Disabled when ttl workaround is needed, e.g
1356 * when ESWITCH_IPV4_TTL_MODIFY_ENABLE = true in mlxconfig
1357 */
1358 esw_warn(dev,
1359 "Tc chains and priorities offload aren't supported, check firmware version, or mlxconfig settings\n");
1360 *flags &= ~MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1361 } else {
1362 *flags |= MLX5_CHAINS_AND_PRIOS_SUPPORTED;
1363 esw_info(dev, "Supported tc chains and prios offload\n");
1364 }
1365
1366 if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
1367 *flags |= MLX5_CHAINS_FT_TUNNEL_SUPPORTED;
1368 }
1369
1370 static int
esw_chains_create(struct mlx5_eswitch * esw,struct mlx5_flow_table * miss_fdb)1371 esw_chains_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *miss_fdb)
1372 {
1373 struct mlx5_core_dev *dev = esw->dev;
1374 struct mlx5_flow_table *nf_ft, *ft;
1375 struct mlx5_chains_attr attr = {};
1376 struct mlx5_fs_chains *chains;
1377 u32 fdb_max;
1378 int err;
1379
1380 fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size);
1381
1382 esw_init_chains_offload_flags(esw, &attr.flags);
1383 attr.ns = MLX5_FLOW_NAMESPACE_FDB;
1384 attr.max_ft_sz = fdb_max;
1385 attr.max_grp_num = esw->params.large_group_num;
1386 attr.default_ft = miss_fdb;
1387 attr.mapping = esw->offloads.reg_c0_obj_pool;
1388
1389 chains = mlx5_chains_create(dev, &attr);
1390 if (IS_ERR(chains)) {
1391 err = PTR_ERR(chains);
1392 esw_warn(dev, "Failed to create fdb chains err(%d)\n", err);
1393 return err;
1394 }
1395
1396 esw->fdb_table.offloads.esw_chains_priv = chains;
1397
1398 /* Create tc_end_ft which is the always created ft chain */
1399 nf_ft = mlx5_chains_get_table(chains, mlx5_chains_get_nf_ft_chain(chains),
1400 1, 0);
1401 if (IS_ERR(nf_ft)) {
1402 err = PTR_ERR(nf_ft);
1403 goto nf_ft_err;
1404 }
1405
1406 /* Always open the root for fast path */
1407 ft = mlx5_chains_get_table(chains, 0, 1, 0);
1408 if (IS_ERR(ft)) {
1409 err = PTR_ERR(ft);
1410 goto level_0_err;
1411 }
1412
1413 /* Open level 1 for split fdb rules now if prios isn't supported */
1414 if (!mlx5_chains_prios_supported(chains)) {
1415 err = esw_vport_tbl_get(esw);
1416 if (err)
1417 goto level_1_err;
1418 }
1419
1420 mlx5_chains_set_end_ft(chains, nf_ft);
1421
1422 return 0;
1423
1424 level_1_err:
1425 mlx5_chains_put_table(chains, 0, 1, 0);
1426 level_0_err:
1427 mlx5_chains_put_table(chains, mlx5_chains_get_nf_ft_chain(chains), 1, 0);
1428 nf_ft_err:
1429 mlx5_chains_destroy(chains);
1430 esw->fdb_table.offloads.esw_chains_priv = NULL;
1431
1432 return err;
1433 }
1434
1435 static void
esw_chains_destroy(struct mlx5_eswitch * esw,struct mlx5_fs_chains * chains)1436 esw_chains_destroy(struct mlx5_eswitch *esw, struct mlx5_fs_chains *chains)
1437 {
1438 if (!mlx5_chains_prios_supported(chains))
1439 esw_vport_tbl_put(esw);
1440 mlx5_chains_put_table(chains, 0, 1, 0);
1441 mlx5_chains_put_table(chains, mlx5_chains_get_nf_ft_chain(chains), 1, 0);
1442 mlx5_chains_destroy(chains);
1443 }
1444
1445 #else /* CONFIG_MLX5_CLS_ACT */
1446
1447 static int
esw_chains_create(struct mlx5_eswitch * esw,struct mlx5_flow_table * miss_fdb)1448 esw_chains_create(struct mlx5_eswitch *esw, struct mlx5_flow_table *miss_fdb)
1449 { return 0; }
1450
1451 static void
esw_chains_destroy(struct mlx5_eswitch * esw,struct mlx5_fs_chains * chains)1452 esw_chains_destroy(struct mlx5_eswitch *esw, struct mlx5_fs_chains *chains)
1453 {}
1454
1455 #endif
1456
1457 static int
esw_create_send_to_vport_group(struct mlx5_eswitch * esw,struct mlx5_flow_table * fdb,u32 * flow_group_in,int * ix)1458 esw_create_send_to_vport_group(struct mlx5_eswitch *esw,
1459 struct mlx5_flow_table *fdb,
1460 u32 *flow_group_in,
1461 int *ix)
1462 {
1463 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1464 struct mlx5_flow_group *g;
1465 void *match_criteria;
1466 int count, err = 0;
1467
1468 memset(flow_group_in, 0, inlen);
1469
1470 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1471 MLX5_MATCH_MISC_PARAMETERS);
1472
1473 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1474
1475 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
1476 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
1477 if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) {
1478 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1479 misc_parameters.source_eswitch_owner_vhca_id);
1480 MLX5_SET(create_flow_group_in, flow_group_in,
1481 source_eswitch_owner_vhca_id_valid, 1);
1482 }
1483
1484 /* See comment at table_size calculation */
1485 count = MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ);
1486 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1487 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, *ix + count - 1);
1488 *ix += count;
1489
1490 g = mlx5_create_flow_group(fdb, flow_group_in);
1491 if (IS_ERR(g)) {
1492 err = PTR_ERR(g);
1493 esw_warn(esw->dev, "Failed to create send-to-vport flow group err(%d)\n", err);
1494 goto out;
1495 }
1496 esw->fdb_table.offloads.send_to_vport_grp = g;
1497
1498 out:
1499 return err;
1500 }
1501
1502 static int
esw_create_meta_send_to_vport_group(struct mlx5_eswitch * esw,struct mlx5_flow_table * fdb,u32 * flow_group_in,int * ix)1503 esw_create_meta_send_to_vport_group(struct mlx5_eswitch *esw,
1504 struct mlx5_flow_table *fdb,
1505 u32 *flow_group_in,
1506 int *ix)
1507 {
1508 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1509 struct mlx5_flow_group *g;
1510 void *match_criteria;
1511 int err = 0;
1512
1513 if (!esw_src_port_rewrite_supported(esw))
1514 return 0;
1515
1516 memset(flow_group_in, 0, inlen);
1517
1518 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1519 MLX5_MATCH_MISC_PARAMETERS_2);
1520
1521 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1522
1523 MLX5_SET(fte_match_param, match_criteria,
1524 misc_parameters_2.metadata_reg_c_0,
1525 mlx5_eswitch_get_vport_metadata_mask());
1526 MLX5_SET(fte_match_param, match_criteria,
1527 misc_parameters_2.metadata_reg_c_1, ESW_TUN_MASK);
1528
1529 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, *ix);
1530 MLX5_SET(create_flow_group_in, flow_group_in,
1531 end_flow_index, *ix + esw->total_vports - 1);
1532 *ix += esw->total_vports;
1533
1534 g = mlx5_create_flow_group(fdb, flow_group_in);
1535 if (IS_ERR(g)) {
1536 err = PTR_ERR(g);
1537 esw_warn(esw->dev,
1538 "Failed to create send-to-vport meta flow group err(%d)\n", err);
1539 goto send_vport_meta_err;
1540 }
1541 esw->fdb_table.offloads.send_to_vport_meta_grp = g;
1542
1543 return 0;
1544
1545 send_vport_meta_err:
1546 return err;
1547 }
1548
1549 static int
esw_create_peer_esw_miss_group(struct mlx5_eswitch * esw,struct mlx5_flow_table * fdb,u32 * flow_group_in,int * ix)1550 esw_create_peer_esw_miss_group(struct mlx5_eswitch *esw,
1551 struct mlx5_flow_table *fdb,
1552 u32 *flow_group_in,
1553 int *ix)
1554 {
1555 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1556 struct mlx5_flow_group *g;
1557 void *match_criteria;
1558 int err = 0;
1559
1560 if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
1561 return 0;
1562
1563 memset(flow_group_in, 0, inlen);
1564
1565 esw_set_flow_group_source_port(esw, flow_group_in);
1566
1567 if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1568 match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1569 flow_group_in,
1570 match_criteria);
1571
1572 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1573 misc_parameters.source_eswitch_owner_vhca_id);
1574
1575 MLX5_SET(create_flow_group_in, flow_group_in,
1576 source_eswitch_owner_vhca_id_valid, 1);
1577 }
1578
1579 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, *ix);
1580 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1581 *ix + esw->total_vports - 1);
1582 *ix += esw->total_vports;
1583
1584 g = mlx5_create_flow_group(fdb, flow_group_in);
1585 if (IS_ERR(g)) {
1586 err = PTR_ERR(g);
1587 esw_warn(esw->dev, "Failed to create peer miss flow group err(%d)\n", err);
1588 goto out;
1589 }
1590 esw->fdb_table.offloads.peer_miss_grp = g;
1591
1592 out:
1593 return err;
1594 }
1595
1596 static int
esw_create_miss_group(struct mlx5_eswitch * esw,struct mlx5_flow_table * fdb,u32 * flow_group_in,int * ix)1597 esw_create_miss_group(struct mlx5_eswitch *esw,
1598 struct mlx5_flow_table *fdb,
1599 u32 *flow_group_in,
1600 int *ix)
1601 {
1602 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1603 struct mlx5_flow_group *g;
1604 void *match_criteria;
1605 int err = 0;
1606 u8 *dmac;
1607
1608 memset(flow_group_in, 0, inlen);
1609
1610 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1611 MLX5_MATCH_OUTER_HEADERS);
1612 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
1613 match_criteria);
1614 dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
1615 outer_headers.dmac_47_16);
1616 dmac[0] = 0x01;
1617
1618 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, *ix);
1619 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1620 *ix + MLX5_ESW_MISS_FLOWS);
1621
1622 g = mlx5_create_flow_group(fdb, flow_group_in);
1623 if (IS_ERR(g)) {
1624 err = PTR_ERR(g);
1625 esw_warn(esw->dev, "Failed to create miss flow group err(%d)\n", err);
1626 goto miss_err;
1627 }
1628 esw->fdb_table.offloads.miss_grp = g;
1629
1630 err = esw_add_fdb_miss_rule(esw);
1631 if (err)
1632 goto miss_rule_err;
1633
1634 return 0;
1635
1636 miss_rule_err:
1637 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1638 miss_err:
1639 return err;
1640 }
1641
esw_create_offloads_fdb_tables(struct mlx5_eswitch * esw)1642 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw)
1643 {
1644 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1645 struct mlx5_flow_table_attr ft_attr = {};
1646 struct mlx5_core_dev *dev = esw->dev;
1647 struct mlx5_flow_namespace *root_ns;
1648 struct mlx5_flow_table *fdb = NULL;
1649 int table_size, ix = 0, err = 0;
1650 u32 flags = 0, *flow_group_in;
1651
1652 esw_debug(esw->dev, "Create offloads FDB Tables\n");
1653
1654 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1655 if (!flow_group_in)
1656 return -ENOMEM;
1657
1658 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
1659 if (!root_ns) {
1660 esw_warn(dev, "Failed to get FDB flow namespace\n");
1661 err = -EOPNOTSUPP;
1662 goto ns_err;
1663 }
1664 esw->fdb_table.offloads.ns = root_ns;
1665 err = mlx5_flow_namespace_set_mode(root_ns,
1666 esw->dev->priv.steering->mode);
1667 if (err) {
1668 esw_warn(dev, "Failed to set FDB namespace steering mode\n");
1669 goto ns_err;
1670 }
1671
1672 /* To be strictly correct:
1673 * MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ)
1674 * should be:
1675 * esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ +
1676 * peer_esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ
1677 * but as the peer device might not be in switchdev mode it's not
1678 * possible. We use the fact that by default FW sets max vfs and max sfs
1679 * to the same value on both devices. If it needs to be changed in the future note
1680 * the peer miss group should also be created based on the number of
1681 * total vports of the peer (currently is also uses esw->total_vports).
1682 */
1683 table_size = MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ) +
1684 esw->total_vports * 2 + MLX5_ESW_MISS_FLOWS;
1685
1686 /* create the slow path fdb with encap set, so further table instances
1687 * can be created at run time while VFs are probed if the FW allows that.
1688 */
1689 if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
1690 flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
1691 MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
1692
1693 ft_attr.flags = flags;
1694 ft_attr.max_fte = table_size;
1695 ft_attr.prio = FDB_SLOW_PATH;
1696
1697 fdb = mlx5_create_flow_table(root_ns, &ft_attr);
1698 if (IS_ERR(fdb)) {
1699 err = PTR_ERR(fdb);
1700 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
1701 goto slow_fdb_err;
1702 }
1703 esw->fdb_table.offloads.slow_fdb = fdb;
1704
1705 /* Create empty TC-miss managed table. This allows plugging in following
1706 * priorities without directly exposing their level 0 table to
1707 * eswitch_offloads and passing it as miss_fdb to following call to
1708 * esw_chains_create().
1709 */
1710 memset(&ft_attr, 0, sizeof(ft_attr));
1711 ft_attr.prio = FDB_TC_MISS;
1712 esw->fdb_table.offloads.tc_miss_table = mlx5_create_flow_table(root_ns, &ft_attr);
1713 if (IS_ERR(esw->fdb_table.offloads.tc_miss_table)) {
1714 err = PTR_ERR(esw->fdb_table.offloads.tc_miss_table);
1715 esw_warn(dev, "Failed to create TC miss FDB Table err %d\n", err);
1716 goto tc_miss_table_err;
1717 }
1718
1719 err = esw_chains_create(esw, esw->fdb_table.offloads.tc_miss_table);
1720 if (err) {
1721 esw_warn(dev, "Failed to open fdb chains err(%d)\n", err);
1722 goto fdb_chains_err;
1723 }
1724
1725 err = esw_create_send_to_vport_group(esw, fdb, flow_group_in, &ix);
1726 if (err)
1727 goto send_vport_err;
1728
1729 err = esw_create_meta_send_to_vport_group(esw, fdb, flow_group_in, &ix);
1730 if (err)
1731 goto send_vport_meta_err;
1732
1733 err = esw_create_peer_esw_miss_group(esw, fdb, flow_group_in, &ix);
1734 if (err)
1735 goto peer_miss_err;
1736
1737 err = esw_create_miss_group(esw, fdb, flow_group_in, &ix);
1738 if (err)
1739 goto miss_err;
1740
1741 kvfree(flow_group_in);
1742 return 0;
1743
1744 miss_err:
1745 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
1746 mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1747 peer_miss_err:
1748 if (esw->fdb_table.offloads.send_to_vport_meta_grp)
1749 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_meta_grp);
1750 send_vport_meta_err:
1751 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1752 send_vport_err:
1753 esw_chains_destroy(esw, esw_chains(esw));
1754 fdb_chains_err:
1755 mlx5_destroy_flow_table(esw->fdb_table.offloads.tc_miss_table);
1756 tc_miss_table_err:
1757 mlx5_destroy_flow_table(mlx5_eswitch_get_slow_fdb(esw));
1758 slow_fdb_err:
1759 /* Holds true only as long as DMFS is the default */
1760 mlx5_flow_namespace_set_mode(root_ns, MLX5_FLOW_STEERING_MODE_DMFS);
1761 ns_err:
1762 kvfree(flow_group_in);
1763 return err;
1764 }
1765
esw_destroy_offloads_fdb_tables(struct mlx5_eswitch * esw)1766 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
1767 {
1768 if (!mlx5_eswitch_get_slow_fdb(esw))
1769 return;
1770
1771 esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
1772 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
1773 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
1774 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1775 if (esw->fdb_table.offloads.send_to_vport_meta_grp)
1776 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_meta_grp);
1777 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
1778 mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1779 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1780
1781 esw_chains_destroy(esw, esw_chains(esw));
1782
1783 mlx5_destroy_flow_table(esw->fdb_table.offloads.tc_miss_table);
1784 mlx5_destroy_flow_table(mlx5_eswitch_get_slow_fdb(esw));
1785 /* Holds true only as long as DMFS is the default */
1786 mlx5_flow_namespace_set_mode(esw->fdb_table.offloads.ns,
1787 MLX5_FLOW_STEERING_MODE_DMFS);
1788 atomic64_set(&esw->user_count, 0);
1789 }
1790
esw_get_nr_ft_offloads_steering_src_ports(struct mlx5_eswitch * esw)1791 static int esw_get_nr_ft_offloads_steering_src_ports(struct mlx5_eswitch *esw)
1792 {
1793 int nvports;
1794
1795 nvports = esw->total_vports + MLX5_ESW_MISS_FLOWS;
1796 if (mlx5e_tc_int_port_supported(esw))
1797 nvports += MLX5E_TC_MAX_INT_PORT_NUM;
1798
1799 return nvports;
1800 }
1801
esw_create_offloads_table(struct mlx5_eswitch * esw)1802 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
1803 {
1804 struct mlx5_flow_table_attr ft_attr = {};
1805 struct mlx5_core_dev *dev = esw->dev;
1806 struct mlx5_flow_table *ft_offloads;
1807 struct mlx5_flow_namespace *ns;
1808 int err = 0;
1809
1810 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
1811 if (!ns) {
1812 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
1813 return -EOPNOTSUPP;
1814 }
1815
1816 ft_attr.max_fte = esw_get_nr_ft_offloads_steering_src_ports(esw) +
1817 MLX5_ESW_FT_OFFLOADS_DROP_RULE;
1818 ft_attr.prio = 1;
1819
1820 ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
1821 if (IS_ERR(ft_offloads)) {
1822 err = PTR_ERR(ft_offloads);
1823 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
1824 return err;
1825 }
1826
1827 esw->offloads.ft_offloads = ft_offloads;
1828 return 0;
1829 }
1830
esw_destroy_offloads_table(struct mlx5_eswitch * esw)1831 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
1832 {
1833 struct mlx5_esw_offload *offloads = &esw->offloads;
1834
1835 mlx5_destroy_flow_table(offloads->ft_offloads);
1836 }
1837
esw_create_vport_rx_group(struct mlx5_eswitch * esw)1838 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
1839 {
1840 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1841 struct mlx5_flow_group *g;
1842 u32 *flow_group_in;
1843 int nvports;
1844 int err = 0;
1845
1846 nvports = esw_get_nr_ft_offloads_steering_src_ports(esw);
1847 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1848 if (!flow_group_in)
1849 return -ENOMEM;
1850
1851 /* create vport rx group */
1852 esw_set_flow_group_source_port(esw, flow_group_in);
1853
1854 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1855 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
1856
1857 g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
1858
1859 if (IS_ERR(g)) {
1860 err = PTR_ERR(g);
1861 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
1862 goto out;
1863 }
1864
1865 esw->offloads.vport_rx_group = g;
1866 out:
1867 kvfree(flow_group_in);
1868 return err;
1869 }
1870
esw_destroy_vport_rx_group(struct mlx5_eswitch * esw)1871 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
1872 {
1873 mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
1874 }
1875
esw_create_vport_rx_drop_rule_index(struct mlx5_eswitch * esw)1876 static int esw_create_vport_rx_drop_rule_index(struct mlx5_eswitch *esw)
1877 {
1878 /* ft_offloads table is enlarged by MLX5_ESW_FT_OFFLOADS_DROP_RULE (1)
1879 * for the drop rule, which is placed at the end of the table.
1880 * So return the total of vport and int_port as rule index.
1881 */
1882 return esw_get_nr_ft_offloads_steering_src_ports(esw);
1883 }
1884
esw_create_vport_rx_drop_group(struct mlx5_eswitch * esw)1885 static int esw_create_vport_rx_drop_group(struct mlx5_eswitch *esw)
1886 {
1887 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1888 struct mlx5_flow_group *g;
1889 u32 *flow_group_in;
1890 int flow_index;
1891 int err = 0;
1892
1893 flow_index = esw_create_vport_rx_drop_rule_index(esw);
1894
1895 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1896 if (!flow_group_in)
1897 return -ENOMEM;
1898
1899 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_index);
1900 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_index);
1901
1902 g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
1903
1904 if (IS_ERR(g)) {
1905 err = PTR_ERR(g);
1906 mlx5_core_warn(esw->dev, "Failed to create vport rx drop group err %d\n", err);
1907 goto out;
1908 }
1909
1910 esw->offloads.vport_rx_drop_group = g;
1911 out:
1912 kvfree(flow_group_in);
1913 return err;
1914 }
1915
esw_destroy_vport_rx_drop_group(struct mlx5_eswitch * esw)1916 static void esw_destroy_vport_rx_drop_group(struct mlx5_eswitch *esw)
1917 {
1918 if (esw->offloads.vport_rx_drop_group)
1919 mlx5_destroy_flow_group(esw->offloads.vport_rx_drop_group);
1920 }
1921
1922 struct mlx5_flow_handle *
mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch * esw,u16 vport,struct mlx5_flow_destination * dest)1923 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport,
1924 struct mlx5_flow_destination *dest)
1925 {
1926 struct mlx5_flow_act flow_act = {0};
1927 struct mlx5_flow_handle *flow_rule;
1928 struct mlx5_flow_spec *spec;
1929 void *misc;
1930
1931 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1932 if (!spec) {
1933 flow_rule = ERR_PTR(-ENOMEM);
1934 goto out;
1935 }
1936
1937 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1938 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
1939 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1940 mlx5_eswitch_get_vport_metadata_for_match(esw, vport));
1941
1942 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
1943 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1944 mlx5_eswitch_get_vport_metadata_mask());
1945
1946 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1947 } else {
1948 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
1949 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
1950
1951 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
1952 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1953
1954 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
1955 }
1956
1957 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1958 flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
1959 &flow_act, dest, 1);
1960 if (IS_ERR(flow_rule)) {
1961 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
1962 goto out;
1963 }
1964
1965 out:
1966 kvfree(spec);
1967 return flow_rule;
1968 }
1969
esw_create_vport_rx_drop_rule(struct mlx5_eswitch * esw)1970 static int esw_create_vport_rx_drop_rule(struct mlx5_eswitch *esw)
1971 {
1972 struct mlx5_flow_act flow_act = {};
1973 struct mlx5_flow_handle *flow_rule;
1974
1975 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
1976 flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, NULL,
1977 &flow_act, NULL, 0);
1978 if (IS_ERR(flow_rule)) {
1979 esw_warn(esw->dev,
1980 "fs offloads: Failed to add vport rx drop rule err %ld\n",
1981 PTR_ERR(flow_rule));
1982 return PTR_ERR(flow_rule);
1983 }
1984
1985 esw->offloads.vport_rx_drop_rule = flow_rule;
1986
1987 return 0;
1988 }
1989
esw_destroy_vport_rx_drop_rule(struct mlx5_eswitch * esw)1990 static void esw_destroy_vport_rx_drop_rule(struct mlx5_eswitch *esw)
1991 {
1992 if (esw->offloads.vport_rx_drop_rule)
1993 mlx5_del_flow_rules(esw->offloads.vport_rx_drop_rule);
1994 }
1995
mlx5_eswitch_inline_mode_get(struct mlx5_eswitch * esw,u8 * mode)1996 static int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
1997 {
1998 u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1999 struct mlx5_core_dev *dev = esw->dev;
2000 struct mlx5_vport *vport;
2001 unsigned long i;
2002
2003 if (!MLX5_CAP_GEN(dev, vport_group_manager))
2004 return -EOPNOTSUPP;
2005
2006 if (!mlx5_esw_is_fdb_created(esw))
2007 return -EOPNOTSUPP;
2008
2009 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
2010 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
2011 mlx5_mode = MLX5_INLINE_MODE_NONE;
2012 goto out;
2013 case MLX5_CAP_INLINE_MODE_L2:
2014 mlx5_mode = MLX5_INLINE_MODE_L2;
2015 goto out;
2016 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
2017 goto query_vports;
2018 }
2019
2020 query_vports:
2021 mlx5_query_nic_vport_min_inline(dev, esw->first_host_vport, &prev_mlx5_mode);
2022 mlx5_esw_for_each_host_func_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
2023 mlx5_query_nic_vport_min_inline(dev, vport->vport, &mlx5_mode);
2024 if (prev_mlx5_mode != mlx5_mode)
2025 return -EINVAL;
2026 prev_mlx5_mode = mlx5_mode;
2027 }
2028
2029 out:
2030 *mode = mlx5_mode;
2031 return 0;
2032 }
2033
esw_destroy_restore_table(struct mlx5_eswitch * esw)2034 static void esw_destroy_restore_table(struct mlx5_eswitch *esw)
2035 {
2036 struct mlx5_esw_offload *offloads = &esw->offloads;
2037
2038 if (!mlx5_eswitch_reg_c1_loopback_supported(esw))
2039 return;
2040
2041 mlx5_modify_header_dealloc(esw->dev, offloads->restore_copy_hdr_id);
2042 mlx5_destroy_flow_group(offloads->restore_group);
2043 mlx5_destroy_flow_table(offloads->ft_offloads_restore);
2044 }
2045
esw_create_restore_table(struct mlx5_eswitch * esw)2046 static int esw_create_restore_table(struct mlx5_eswitch *esw)
2047 {
2048 u8 modact[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
2049 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
2050 struct mlx5_flow_table_attr ft_attr = {};
2051 struct mlx5_core_dev *dev = esw->dev;
2052 struct mlx5_flow_namespace *ns;
2053 struct mlx5_modify_hdr *mod_hdr;
2054 void *match_criteria, *misc;
2055 struct mlx5_flow_table *ft;
2056 struct mlx5_flow_group *g;
2057 u32 *flow_group_in;
2058 int err = 0;
2059
2060 if (!mlx5_eswitch_reg_c1_loopback_supported(esw))
2061 return 0;
2062
2063 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
2064 if (!ns) {
2065 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
2066 return -EOPNOTSUPP;
2067 }
2068
2069 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
2070 if (!flow_group_in) {
2071 err = -ENOMEM;
2072 goto out_free;
2073 }
2074
2075 ft_attr.max_fte = 1 << ESW_REG_C0_USER_DATA_METADATA_BITS;
2076 ft = mlx5_create_flow_table(ns, &ft_attr);
2077 if (IS_ERR(ft)) {
2078 err = PTR_ERR(ft);
2079 esw_warn(esw->dev, "Failed to create restore table, err %d\n",
2080 err);
2081 goto out_free;
2082 }
2083
2084 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
2085 match_criteria);
2086 misc = MLX5_ADDR_OF(fte_match_param, match_criteria,
2087 misc_parameters_2);
2088
2089 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
2090 ESW_REG_C0_USER_DATA_METADATA_MASK);
2091 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
2092 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
2093 ft_attr.max_fte - 1);
2094 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
2095 MLX5_MATCH_MISC_PARAMETERS_2);
2096 g = mlx5_create_flow_group(ft, flow_group_in);
2097 if (IS_ERR(g)) {
2098 err = PTR_ERR(g);
2099 esw_warn(dev, "Failed to create restore flow group, err: %d\n",
2100 err);
2101 goto err_group;
2102 }
2103
2104 MLX5_SET(copy_action_in, modact, action_type, MLX5_ACTION_TYPE_COPY);
2105 MLX5_SET(copy_action_in, modact, src_field,
2106 MLX5_ACTION_IN_FIELD_METADATA_REG_C_1);
2107 MLX5_SET(copy_action_in, modact, dst_field,
2108 MLX5_ACTION_IN_FIELD_METADATA_REG_B);
2109 mod_hdr = mlx5_modify_header_alloc(esw->dev,
2110 MLX5_FLOW_NAMESPACE_KERNEL, 1,
2111 modact);
2112 if (IS_ERR(mod_hdr)) {
2113 err = PTR_ERR(mod_hdr);
2114 esw_warn(dev, "Failed to create restore mod header, err: %d\n",
2115 err);
2116 goto err_mod_hdr;
2117 }
2118
2119 esw->offloads.ft_offloads_restore = ft;
2120 esw->offloads.restore_group = g;
2121 esw->offloads.restore_copy_hdr_id = mod_hdr;
2122
2123 kvfree(flow_group_in);
2124
2125 return 0;
2126
2127 err_mod_hdr:
2128 mlx5_destroy_flow_group(g);
2129 err_group:
2130 mlx5_destroy_flow_table(ft);
2131 out_free:
2132 kvfree(flow_group_in);
2133
2134 return err;
2135 }
2136
esw_offloads_start(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)2137 static int esw_offloads_start(struct mlx5_eswitch *esw,
2138 struct netlink_ext_ack *extack)
2139 {
2140 int err;
2141
2142 esw->mode = MLX5_ESWITCH_OFFLOADS;
2143 err = mlx5_eswitch_enable_locked(esw, esw->dev->priv.sriov.num_vfs);
2144 if (err) {
2145 NL_SET_ERR_MSG_MOD(extack,
2146 "Failed setting eswitch to offloads");
2147 esw->mode = MLX5_ESWITCH_LEGACY;
2148 mlx5_rescan_drivers(esw->dev);
2149 }
2150 if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
2151 if (mlx5_eswitch_inline_mode_get(esw,
2152 &esw->offloads.inline_mode)) {
2153 esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
2154 NL_SET_ERR_MSG_MOD(extack,
2155 "Inline mode is different between vports");
2156 }
2157 }
2158 return err;
2159 }
2160
mlx5_esw_offloads_rep_mark_set(struct mlx5_eswitch * esw,struct mlx5_eswitch_rep * rep,xa_mark_t mark)2161 static void mlx5_esw_offloads_rep_mark_set(struct mlx5_eswitch *esw,
2162 struct mlx5_eswitch_rep *rep,
2163 xa_mark_t mark)
2164 {
2165 bool mark_set;
2166
2167 /* Copy the mark from vport to its rep */
2168 mark_set = xa_get_mark(&esw->vports, rep->vport, mark);
2169 if (mark_set)
2170 xa_set_mark(&esw->offloads.vport_reps, rep->vport, mark);
2171 }
2172
mlx5_esw_offloads_rep_init(struct mlx5_eswitch * esw,const struct mlx5_vport * vport)2173 static int mlx5_esw_offloads_rep_init(struct mlx5_eswitch *esw, const struct mlx5_vport *vport)
2174 {
2175 struct mlx5_eswitch_rep *rep;
2176 int rep_type;
2177 int err;
2178
2179 rep = kzalloc(sizeof(*rep), GFP_KERNEL);
2180 if (!rep)
2181 return -ENOMEM;
2182
2183 rep->vport = vport->vport;
2184 rep->vport_index = vport->index;
2185 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
2186 atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
2187
2188 err = xa_insert(&esw->offloads.vport_reps, rep->vport, rep, GFP_KERNEL);
2189 if (err)
2190 goto insert_err;
2191
2192 mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_HOST_FN);
2193 mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_VF);
2194 mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_SF);
2195 return 0;
2196
2197 insert_err:
2198 kfree(rep);
2199 return err;
2200 }
2201
mlx5_esw_offloads_rep_cleanup(struct mlx5_eswitch * esw,struct mlx5_eswitch_rep * rep)2202 static void mlx5_esw_offloads_rep_cleanup(struct mlx5_eswitch *esw,
2203 struct mlx5_eswitch_rep *rep)
2204 {
2205 xa_erase(&esw->offloads.vport_reps, rep->vport);
2206 kfree(rep);
2207 }
2208
esw_offloads_cleanup_reps(struct mlx5_eswitch * esw)2209 static void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
2210 {
2211 struct mlx5_eswitch_rep *rep;
2212 unsigned long i;
2213
2214 mlx5_esw_for_each_rep(esw, i, rep)
2215 mlx5_esw_offloads_rep_cleanup(esw, rep);
2216 xa_destroy(&esw->offloads.vport_reps);
2217 }
2218
esw_offloads_init_reps(struct mlx5_eswitch * esw)2219 static int esw_offloads_init_reps(struct mlx5_eswitch *esw)
2220 {
2221 struct mlx5_vport *vport;
2222 unsigned long i;
2223 int err;
2224
2225 xa_init(&esw->offloads.vport_reps);
2226
2227 mlx5_esw_for_each_vport(esw, i, vport) {
2228 err = mlx5_esw_offloads_rep_init(esw, vport);
2229 if (err)
2230 goto err;
2231 }
2232 return 0;
2233
2234 err:
2235 esw_offloads_cleanup_reps(esw);
2236 return err;
2237 }
2238
esw_port_metadata_set(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx)2239 static int esw_port_metadata_set(struct devlink *devlink, u32 id,
2240 struct devlink_param_gset_ctx *ctx)
2241 {
2242 struct mlx5_core_dev *dev = devlink_priv(devlink);
2243 struct mlx5_eswitch *esw = dev->priv.eswitch;
2244 int err = 0;
2245
2246 down_write(&esw->mode_lock);
2247 if (mlx5_esw_is_fdb_created(esw)) {
2248 err = -EBUSY;
2249 goto done;
2250 }
2251 if (!mlx5_esw_vport_match_metadata_supported(esw)) {
2252 err = -EOPNOTSUPP;
2253 goto done;
2254 }
2255 if (ctx->val.vbool)
2256 esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
2257 else
2258 esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA;
2259 done:
2260 up_write(&esw->mode_lock);
2261 return err;
2262 }
2263
esw_port_metadata_get(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx)2264 static int esw_port_metadata_get(struct devlink *devlink, u32 id,
2265 struct devlink_param_gset_ctx *ctx)
2266 {
2267 struct mlx5_core_dev *dev = devlink_priv(devlink);
2268
2269 ctx->val.vbool = mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch);
2270 return 0;
2271 }
2272
esw_port_metadata_validate(struct devlink * devlink,u32 id,union devlink_param_value val,struct netlink_ext_ack * extack)2273 static int esw_port_metadata_validate(struct devlink *devlink, u32 id,
2274 union devlink_param_value val,
2275 struct netlink_ext_ack *extack)
2276 {
2277 struct mlx5_core_dev *dev = devlink_priv(devlink);
2278 u8 esw_mode;
2279
2280 esw_mode = mlx5_eswitch_mode(dev);
2281 if (esw_mode == MLX5_ESWITCH_OFFLOADS) {
2282 NL_SET_ERR_MSG_MOD(extack,
2283 "E-Switch must either disabled or non switchdev mode");
2284 return -EBUSY;
2285 }
2286 return 0;
2287 }
2288
2289 static const struct devlink_param esw_devlink_params[] = {
2290 DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_ESW_PORT_METADATA,
2291 "esw_port_metadata", DEVLINK_PARAM_TYPE_BOOL,
2292 BIT(DEVLINK_PARAM_CMODE_RUNTIME),
2293 esw_port_metadata_get,
2294 esw_port_metadata_set,
2295 esw_port_metadata_validate),
2296 };
2297
esw_offloads_init(struct mlx5_eswitch * esw)2298 int esw_offloads_init(struct mlx5_eswitch *esw)
2299 {
2300 int err;
2301
2302 err = esw_offloads_init_reps(esw);
2303 if (err)
2304 return err;
2305
2306 err = devl_params_register(priv_to_devlink(esw->dev),
2307 esw_devlink_params,
2308 ARRAY_SIZE(esw_devlink_params));
2309 if (err)
2310 goto err_params;
2311
2312 return 0;
2313
2314 err_params:
2315 esw_offloads_cleanup_reps(esw);
2316 return err;
2317 }
2318
esw_offloads_cleanup(struct mlx5_eswitch * esw)2319 void esw_offloads_cleanup(struct mlx5_eswitch *esw)
2320 {
2321 devl_params_unregister(priv_to_devlink(esw->dev),
2322 esw_devlink_params,
2323 ARRAY_SIZE(esw_devlink_params));
2324 esw_offloads_cleanup_reps(esw);
2325 }
2326
__esw_offloads_unload_rep(struct mlx5_eswitch * esw,struct mlx5_eswitch_rep * rep,u8 rep_type)2327 static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
2328 struct mlx5_eswitch_rep *rep, u8 rep_type)
2329 {
2330 if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
2331 REP_LOADED, REP_REGISTERED) == REP_LOADED)
2332 esw->offloads.rep_ops[rep_type]->unload(rep);
2333 }
2334
__unload_reps_sf_vport(struct mlx5_eswitch * esw,u8 rep_type)2335 static void __unload_reps_sf_vport(struct mlx5_eswitch *esw, u8 rep_type)
2336 {
2337 struct mlx5_eswitch_rep *rep;
2338 unsigned long i;
2339
2340 mlx5_esw_for_each_sf_rep(esw, i, rep)
2341 __esw_offloads_unload_rep(esw, rep, rep_type);
2342 }
2343
__unload_reps_all_vport(struct mlx5_eswitch * esw,u8 rep_type)2344 static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
2345 {
2346 struct mlx5_eswitch_rep *rep;
2347 unsigned long i;
2348
2349 __unload_reps_sf_vport(esw, rep_type);
2350
2351 mlx5_esw_for_each_vf_rep(esw, i, rep)
2352 __esw_offloads_unload_rep(esw, rep, rep_type);
2353
2354 if (mlx5_ecpf_vport_exists(esw->dev)) {
2355 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_ECPF);
2356 __esw_offloads_unload_rep(esw, rep, rep_type);
2357 }
2358
2359 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
2360 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
2361 __esw_offloads_unload_rep(esw, rep, rep_type);
2362 }
2363
2364 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
2365 __esw_offloads_unload_rep(esw, rep, rep_type);
2366 }
2367
mlx5_esw_offloads_rep_load(struct mlx5_eswitch * esw,u16 vport_num)2368 int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num)
2369 {
2370 struct mlx5_eswitch_rep *rep;
2371 int rep_type;
2372 int err;
2373
2374 rep = mlx5_eswitch_get_rep(esw, vport_num);
2375 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
2376 if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
2377 REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
2378 err = esw->offloads.rep_ops[rep_type]->load(esw->dev, rep);
2379 if (err)
2380 goto err_reps;
2381 }
2382
2383 return 0;
2384
2385 err_reps:
2386 atomic_set(&rep->rep_data[rep_type].state, REP_REGISTERED);
2387 for (--rep_type; rep_type >= 0; rep_type--)
2388 __esw_offloads_unload_rep(esw, rep, rep_type);
2389 return err;
2390 }
2391
mlx5_esw_offloads_rep_unload(struct mlx5_eswitch * esw,u16 vport_num)2392 void mlx5_esw_offloads_rep_unload(struct mlx5_eswitch *esw, u16 vport_num)
2393 {
2394 struct mlx5_eswitch_rep *rep;
2395 int rep_type;
2396
2397 rep = mlx5_eswitch_get_rep(esw, vport_num);
2398 for (rep_type = NUM_REP_TYPES - 1; rep_type >= 0; rep_type--)
2399 __esw_offloads_unload_rep(esw, rep, rep_type);
2400 }
2401
esw_offloads_load_rep(struct mlx5_eswitch * esw,u16 vport_num)2402 int esw_offloads_load_rep(struct mlx5_eswitch *esw, u16 vport_num)
2403 {
2404 int err;
2405
2406 if (esw->mode != MLX5_ESWITCH_OFFLOADS)
2407 return 0;
2408
2409 if (vport_num != MLX5_VPORT_UPLINK) {
2410 err = mlx5_esw_offloads_devlink_port_register(esw, vport_num);
2411 if (err)
2412 return err;
2413 }
2414
2415 err = mlx5_esw_offloads_rep_load(esw, vport_num);
2416 if (err)
2417 goto load_err;
2418 return err;
2419
2420 load_err:
2421 if (vport_num != MLX5_VPORT_UPLINK)
2422 mlx5_esw_offloads_devlink_port_unregister(esw, vport_num);
2423 return err;
2424 }
2425
esw_offloads_unload_rep(struct mlx5_eswitch * esw,u16 vport_num)2426 void esw_offloads_unload_rep(struct mlx5_eswitch *esw, u16 vport_num)
2427 {
2428 if (esw->mode != MLX5_ESWITCH_OFFLOADS)
2429 return;
2430
2431 mlx5_esw_offloads_rep_unload(esw, vport_num);
2432
2433 if (vport_num != MLX5_VPORT_UPLINK)
2434 mlx5_esw_offloads_devlink_port_unregister(esw, vport_num);
2435 }
2436
esw_set_slave_root_fdb(struct mlx5_core_dev * master,struct mlx5_core_dev * slave)2437 static int esw_set_slave_root_fdb(struct mlx5_core_dev *master,
2438 struct mlx5_core_dev *slave)
2439 {
2440 u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)] = {};
2441 u32 out[MLX5_ST_SZ_DW(set_flow_table_root_out)] = {};
2442 struct mlx5_flow_root_namespace *root;
2443 struct mlx5_flow_namespace *ns;
2444 int err;
2445
2446 MLX5_SET(set_flow_table_root_in, in, opcode,
2447 MLX5_CMD_OP_SET_FLOW_TABLE_ROOT);
2448 MLX5_SET(set_flow_table_root_in, in, table_type,
2449 FS_FT_FDB);
2450
2451 if (master) {
2452 ns = mlx5_get_flow_namespace(master,
2453 MLX5_FLOW_NAMESPACE_FDB);
2454 root = find_root(&ns->node);
2455 mutex_lock(&root->chain_lock);
2456 MLX5_SET(set_flow_table_root_in, in,
2457 table_eswitch_owner_vhca_id_valid, 1);
2458 MLX5_SET(set_flow_table_root_in, in,
2459 table_eswitch_owner_vhca_id,
2460 MLX5_CAP_GEN(master, vhca_id));
2461 MLX5_SET(set_flow_table_root_in, in, table_id,
2462 root->root_ft->id);
2463 } else {
2464 ns = mlx5_get_flow_namespace(slave,
2465 MLX5_FLOW_NAMESPACE_FDB);
2466 root = find_root(&ns->node);
2467 mutex_lock(&root->chain_lock);
2468 MLX5_SET(set_flow_table_root_in, in, table_id,
2469 root->root_ft->id);
2470 }
2471
2472 err = mlx5_cmd_exec(slave, in, sizeof(in), out, sizeof(out));
2473 mutex_unlock(&root->chain_lock);
2474
2475 return err;
2476 }
2477
__esw_set_master_egress_rule(struct mlx5_core_dev * master,struct mlx5_core_dev * slave,struct mlx5_vport * vport,struct mlx5_flow_table * acl)2478 static int __esw_set_master_egress_rule(struct mlx5_core_dev *master,
2479 struct mlx5_core_dev *slave,
2480 struct mlx5_vport *vport,
2481 struct mlx5_flow_table *acl)
2482 {
2483 struct mlx5_flow_handle *flow_rule = NULL;
2484 struct mlx5_flow_destination dest = {};
2485 struct mlx5_flow_act flow_act = {};
2486 struct mlx5_flow_spec *spec;
2487 int err = 0;
2488 void *misc;
2489
2490 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
2491 if (!spec)
2492 return -ENOMEM;
2493
2494 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
2495 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
2496 misc_parameters);
2497 MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_UPLINK);
2498 MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
2499 MLX5_CAP_GEN(slave, vhca_id));
2500
2501 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
2502 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
2503 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
2504 source_eswitch_owner_vhca_id);
2505
2506 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2507 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
2508 dest.vport.num = slave->priv.eswitch->manager_vport;
2509 dest.vport.vhca_id = MLX5_CAP_GEN(slave, vhca_id);
2510 dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
2511
2512 flow_rule = mlx5_add_flow_rules(acl, spec, &flow_act,
2513 &dest, 1);
2514 if (IS_ERR(flow_rule))
2515 err = PTR_ERR(flow_rule);
2516 else
2517 vport->egress.offloads.bounce_rule = flow_rule;
2518
2519 kvfree(spec);
2520 return err;
2521 }
2522
esw_set_master_egress_rule(struct mlx5_core_dev * master,struct mlx5_core_dev * slave)2523 static int esw_set_master_egress_rule(struct mlx5_core_dev *master,
2524 struct mlx5_core_dev *slave)
2525 {
2526 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
2527 struct mlx5_eswitch *esw = master->priv.eswitch;
2528 struct mlx5_flow_table_attr ft_attr = {
2529 .max_fte = 1, .prio = 0, .level = 0,
2530 .flags = MLX5_FLOW_TABLE_OTHER_VPORT,
2531 };
2532 struct mlx5_flow_namespace *egress_ns;
2533 struct mlx5_flow_table *acl;
2534 struct mlx5_flow_group *g;
2535 struct mlx5_vport *vport;
2536 void *match_criteria;
2537 u32 *flow_group_in;
2538 int err;
2539
2540 vport = mlx5_eswitch_get_vport(esw, esw->manager_vport);
2541 if (IS_ERR(vport))
2542 return PTR_ERR(vport);
2543
2544 egress_ns = mlx5_get_flow_vport_acl_namespace(master,
2545 MLX5_FLOW_NAMESPACE_ESW_EGRESS,
2546 vport->index);
2547 if (!egress_ns)
2548 return -EINVAL;
2549
2550 if (vport->egress.acl)
2551 return -EINVAL;
2552
2553 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
2554 if (!flow_group_in)
2555 return -ENOMEM;
2556
2557 acl = mlx5_create_vport_flow_table(egress_ns, &ft_attr, vport->vport);
2558 if (IS_ERR(acl)) {
2559 err = PTR_ERR(acl);
2560 goto out;
2561 }
2562
2563 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
2564 match_criteria);
2565 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
2566 misc_parameters.source_port);
2567 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
2568 misc_parameters.source_eswitch_owner_vhca_id);
2569 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
2570 MLX5_MATCH_MISC_PARAMETERS);
2571
2572 MLX5_SET(create_flow_group_in, flow_group_in,
2573 source_eswitch_owner_vhca_id_valid, 1);
2574 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
2575 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
2576
2577 g = mlx5_create_flow_group(acl, flow_group_in);
2578 if (IS_ERR(g)) {
2579 err = PTR_ERR(g);
2580 goto err_group;
2581 }
2582
2583 err = __esw_set_master_egress_rule(master, slave, vport, acl);
2584 if (err)
2585 goto err_rule;
2586
2587 vport->egress.acl = acl;
2588 vport->egress.offloads.bounce_grp = g;
2589
2590 kvfree(flow_group_in);
2591
2592 return 0;
2593
2594 err_rule:
2595 mlx5_destroy_flow_group(g);
2596 err_group:
2597 mlx5_destroy_flow_table(acl);
2598 out:
2599 kvfree(flow_group_in);
2600 return err;
2601 }
2602
esw_unset_master_egress_rule(struct mlx5_core_dev * dev)2603 static void esw_unset_master_egress_rule(struct mlx5_core_dev *dev)
2604 {
2605 struct mlx5_vport *vport;
2606
2607 vport = mlx5_eswitch_get_vport(dev->priv.eswitch,
2608 dev->priv.eswitch->manager_vport);
2609
2610 esw_acl_egress_ofld_cleanup(vport);
2611 }
2612
mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch * master_esw,struct mlx5_eswitch * slave_esw)2613 int mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch *master_esw,
2614 struct mlx5_eswitch *slave_esw)
2615 {
2616 int err;
2617
2618 err = esw_set_slave_root_fdb(master_esw->dev,
2619 slave_esw->dev);
2620 if (err)
2621 return err;
2622
2623 err = esw_set_master_egress_rule(master_esw->dev,
2624 slave_esw->dev);
2625 if (err)
2626 goto err_acl;
2627
2628 return err;
2629
2630 err_acl:
2631 esw_set_slave_root_fdb(NULL, slave_esw->dev);
2632
2633 return err;
2634 }
2635
mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch * master_esw,struct mlx5_eswitch * slave_esw)2636 void mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch *master_esw,
2637 struct mlx5_eswitch *slave_esw)
2638 {
2639 esw_unset_master_egress_rule(master_esw->dev);
2640 esw_set_slave_root_fdb(NULL, slave_esw->dev);
2641 }
2642
2643 #define ESW_OFFLOADS_DEVCOM_PAIR (0)
2644 #define ESW_OFFLOADS_DEVCOM_UNPAIR (1)
2645
mlx5_esw_offloads_rep_event_unpair(struct mlx5_eswitch * esw)2646 static void mlx5_esw_offloads_rep_event_unpair(struct mlx5_eswitch *esw)
2647 {
2648 const struct mlx5_eswitch_rep_ops *ops;
2649 struct mlx5_eswitch_rep *rep;
2650 unsigned long i;
2651 u8 rep_type;
2652
2653 mlx5_esw_for_each_rep(esw, i, rep) {
2654 rep_type = NUM_REP_TYPES;
2655 while (rep_type--) {
2656 ops = esw->offloads.rep_ops[rep_type];
2657 if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
2658 ops->event)
2659 ops->event(esw, rep, MLX5_SWITCHDEV_EVENT_UNPAIR, NULL);
2660 }
2661 }
2662 }
2663
mlx5_esw_offloads_unpair(struct mlx5_eswitch * esw)2664 static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw)
2665 {
2666 #if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
2667 mlx5e_tc_clean_fdb_peer_flows(esw);
2668 #endif
2669 mlx5_esw_offloads_rep_event_unpair(esw);
2670 esw_del_fdb_peer_miss_rules(esw);
2671 }
2672
mlx5_esw_offloads_pair(struct mlx5_eswitch * esw,struct mlx5_eswitch * peer_esw)2673 static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw,
2674 struct mlx5_eswitch *peer_esw)
2675 {
2676 const struct mlx5_eswitch_rep_ops *ops;
2677 struct mlx5_eswitch_rep *rep;
2678 unsigned long i;
2679 u8 rep_type;
2680 int err;
2681
2682 err = esw_add_fdb_peer_miss_rules(esw, peer_esw->dev);
2683 if (err)
2684 return err;
2685
2686 mlx5_esw_for_each_rep(esw, i, rep) {
2687 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
2688 ops = esw->offloads.rep_ops[rep_type];
2689 if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
2690 ops->event) {
2691 err = ops->event(esw, rep, MLX5_SWITCHDEV_EVENT_PAIR, peer_esw);
2692 if (err)
2693 goto err_out;
2694 }
2695 }
2696 }
2697
2698 return 0;
2699
2700 err_out:
2701 mlx5_esw_offloads_unpair(esw);
2702 return err;
2703 }
2704
mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch * esw,struct mlx5_eswitch * peer_esw,bool pair)2705 static int mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch *esw,
2706 struct mlx5_eswitch *peer_esw,
2707 bool pair)
2708 {
2709 struct mlx5_flow_root_namespace *peer_ns;
2710 struct mlx5_flow_root_namespace *ns;
2711 int err;
2712
2713 peer_ns = peer_esw->dev->priv.steering->fdb_root_ns;
2714 ns = esw->dev->priv.steering->fdb_root_ns;
2715
2716 if (pair) {
2717 err = mlx5_flow_namespace_set_peer(ns, peer_ns);
2718 if (err)
2719 return err;
2720
2721 err = mlx5_flow_namespace_set_peer(peer_ns, ns);
2722 if (err) {
2723 mlx5_flow_namespace_set_peer(ns, NULL);
2724 return err;
2725 }
2726 } else {
2727 mlx5_flow_namespace_set_peer(ns, NULL);
2728 mlx5_flow_namespace_set_peer(peer_ns, NULL);
2729 }
2730
2731 return 0;
2732 }
2733
mlx5_esw_offloads_devcom_event(int event,void * my_data,void * event_data)2734 static int mlx5_esw_offloads_devcom_event(int event,
2735 void *my_data,
2736 void *event_data)
2737 {
2738 struct mlx5_eswitch *esw = my_data;
2739 struct mlx5_devcom *devcom = esw->dev->priv.devcom;
2740 struct mlx5_eswitch *peer_esw = event_data;
2741 int err;
2742
2743 switch (event) {
2744 case ESW_OFFLOADS_DEVCOM_PAIR:
2745 if (mlx5_eswitch_vport_match_metadata_enabled(esw) !=
2746 mlx5_eswitch_vport_match_metadata_enabled(peer_esw))
2747 break;
2748
2749 err = mlx5_esw_offloads_set_ns_peer(esw, peer_esw, true);
2750 if (err)
2751 goto err_out;
2752 err = mlx5_esw_offloads_pair(esw, peer_esw);
2753 if (err)
2754 goto err_peer;
2755
2756 err = mlx5_esw_offloads_pair(peer_esw, esw);
2757 if (err)
2758 goto err_pair;
2759
2760 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true);
2761 break;
2762
2763 case ESW_OFFLOADS_DEVCOM_UNPAIR:
2764 if (!mlx5_devcom_is_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
2765 break;
2766
2767 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false);
2768 mlx5_esw_offloads_unpair(peer_esw);
2769 mlx5_esw_offloads_unpair(esw);
2770 mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false);
2771 break;
2772 }
2773
2774 return 0;
2775
2776 err_pair:
2777 mlx5_esw_offloads_unpair(esw);
2778 err_peer:
2779 mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false);
2780 err_out:
2781 mlx5_core_err(esw->dev, "esw offloads devcom event failure, event %u err %d",
2782 event, err);
2783 return err;
2784 }
2785
esw_offloads_devcom_init(struct mlx5_eswitch * esw)2786 static void esw_offloads_devcom_init(struct mlx5_eswitch *esw)
2787 {
2788 struct mlx5_devcom *devcom = esw->dev->priv.devcom;
2789
2790 INIT_LIST_HEAD(&esw->offloads.peer_flows);
2791 mutex_init(&esw->offloads.peer_mutex);
2792
2793 if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
2794 return;
2795
2796 if (!mlx5_is_lag_supported(esw->dev))
2797 return;
2798
2799 mlx5_devcom_register_component(devcom,
2800 MLX5_DEVCOM_ESW_OFFLOADS,
2801 mlx5_esw_offloads_devcom_event,
2802 esw);
2803
2804 mlx5_devcom_send_event(devcom,
2805 MLX5_DEVCOM_ESW_OFFLOADS,
2806 ESW_OFFLOADS_DEVCOM_PAIR, esw);
2807 }
2808
esw_offloads_devcom_cleanup(struct mlx5_eswitch * esw)2809 static void esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
2810 {
2811 struct mlx5_devcom *devcom = esw->dev->priv.devcom;
2812
2813 if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
2814 return;
2815
2816 if (!mlx5_is_lag_supported(esw->dev))
2817 return;
2818
2819 mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
2820 ESW_OFFLOADS_DEVCOM_UNPAIR, esw);
2821
2822 mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
2823 }
2824
mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch * esw)2825 bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
2826 {
2827 if (!MLX5_CAP_ESW(esw->dev, esw_uplink_ingress_acl))
2828 return false;
2829
2830 if (!(MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
2831 MLX5_FDB_TO_VPORT_REG_C_0))
2832 return false;
2833
2834 if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
2835 return false;
2836
2837 return true;
2838 }
2839
2840 #define MLX5_ESW_METADATA_RSVD_UPLINK 1
2841
2842 /* Share the same metadata for uplink's. This is fine because:
2843 * (a) In shared FDB mode (LAG) both uplink's are treated the
2844 * same and tagged with the same metadata.
2845 * (b) In non shared FDB mode, packets from physical port0
2846 * cannot hit eswitch of PF1 and vice versa.
2847 */
mlx5_esw_match_metadata_reserved(struct mlx5_eswitch * esw)2848 static u32 mlx5_esw_match_metadata_reserved(struct mlx5_eswitch *esw)
2849 {
2850 return MLX5_ESW_METADATA_RSVD_UPLINK;
2851 }
2852
mlx5_esw_match_metadata_alloc(struct mlx5_eswitch * esw)2853 u32 mlx5_esw_match_metadata_alloc(struct mlx5_eswitch *esw)
2854 {
2855 u32 vport_end_ida = (1 << ESW_VPORT_BITS) - 1;
2856 /* Reserve 0xf for internal port offload */
2857 u32 max_pf_num = (1 << ESW_PFNUM_BITS) - 2;
2858 u32 pf_num;
2859 int id;
2860
2861 /* Only 4 bits of pf_num */
2862 pf_num = mlx5_get_dev_index(esw->dev);
2863 if (pf_num > max_pf_num)
2864 return 0;
2865
2866 /* Metadata is 4 bits of PFNUM and 12 bits of unique id */
2867 /* Use only non-zero vport_id (2-4095) for all PF's */
2868 id = ida_alloc_range(&esw->offloads.vport_metadata_ida,
2869 MLX5_ESW_METADATA_RSVD_UPLINK + 1,
2870 vport_end_ida, GFP_KERNEL);
2871 if (id < 0)
2872 return 0;
2873 id = (pf_num << ESW_VPORT_BITS) | id;
2874 return id;
2875 }
2876
mlx5_esw_match_metadata_free(struct mlx5_eswitch * esw,u32 metadata)2877 void mlx5_esw_match_metadata_free(struct mlx5_eswitch *esw, u32 metadata)
2878 {
2879 u32 vport_bit_mask = (1 << ESW_VPORT_BITS) - 1;
2880
2881 /* Metadata contains only 12 bits of actual ida id */
2882 ida_free(&esw->offloads.vport_metadata_ida, metadata & vport_bit_mask);
2883 }
2884
esw_offloads_vport_metadata_setup(struct mlx5_eswitch * esw,struct mlx5_vport * vport)2885 static int esw_offloads_vport_metadata_setup(struct mlx5_eswitch *esw,
2886 struct mlx5_vport *vport)
2887 {
2888 if (vport->vport == MLX5_VPORT_UPLINK)
2889 vport->default_metadata = mlx5_esw_match_metadata_reserved(esw);
2890 else
2891 vport->default_metadata = mlx5_esw_match_metadata_alloc(esw);
2892
2893 vport->metadata = vport->default_metadata;
2894 return vport->metadata ? 0 : -ENOSPC;
2895 }
2896
esw_offloads_vport_metadata_cleanup(struct mlx5_eswitch * esw,struct mlx5_vport * vport)2897 static void esw_offloads_vport_metadata_cleanup(struct mlx5_eswitch *esw,
2898 struct mlx5_vport *vport)
2899 {
2900 if (!vport->default_metadata)
2901 return;
2902
2903 if (vport->vport == MLX5_VPORT_UPLINK)
2904 return;
2905
2906 WARN_ON(vport->metadata != vport->default_metadata);
2907 mlx5_esw_match_metadata_free(esw, vport->default_metadata);
2908 }
2909
esw_offloads_metadata_uninit(struct mlx5_eswitch * esw)2910 static void esw_offloads_metadata_uninit(struct mlx5_eswitch *esw)
2911 {
2912 struct mlx5_vport *vport;
2913 unsigned long i;
2914
2915 if (!mlx5_eswitch_vport_match_metadata_enabled(esw))
2916 return;
2917
2918 mlx5_esw_for_each_vport(esw, i, vport)
2919 esw_offloads_vport_metadata_cleanup(esw, vport);
2920 }
2921
esw_offloads_metadata_init(struct mlx5_eswitch * esw)2922 static int esw_offloads_metadata_init(struct mlx5_eswitch *esw)
2923 {
2924 struct mlx5_vport *vport;
2925 unsigned long i;
2926 int err;
2927
2928 if (!mlx5_eswitch_vport_match_metadata_enabled(esw))
2929 return 0;
2930
2931 mlx5_esw_for_each_vport(esw, i, vport) {
2932 err = esw_offloads_vport_metadata_setup(esw, vport);
2933 if (err)
2934 goto metadata_err;
2935 }
2936
2937 return 0;
2938
2939 metadata_err:
2940 esw_offloads_metadata_uninit(esw);
2941 return err;
2942 }
2943
mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch * esw,bool enable)2944 int mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch *esw, bool enable)
2945 {
2946 int err = 0;
2947
2948 down_write(&esw->mode_lock);
2949 if (mlx5_esw_is_fdb_created(esw)) {
2950 err = -EBUSY;
2951 goto done;
2952 }
2953 if (!mlx5_esw_vport_match_metadata_supported(esw)) {
2954 err = -EOPNOTSUPP;
2955 goto done;
2956 }
2957 if (enable)
2958 esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
2959 else
2960 esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA;
2961 done:
2962 up_write(&esw->mode_lock);
2963 return err;
2964 }
2965
2966 int
esw_vport_create_offloads_acl_tables(struct mlx5_eswitch * esw,struct mlx5_vport * vport)2967 esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw,
2968 struct mlx5_vport *vport)
2969 {
2970 int err;
2971
2972 err = esw_acl_ingress_ofld_setup(esw, vport);
2973 if (err)
2974 return err;
2975
2976 err = esw_acl_egress_ofld_setup(esw, vport);
2977 if (err)
2978 goto egress_err;
2979
2980 return 0;
2981
2982 egress_err:
2983 esw_acl_ingress_ofld_cleanup(esw, vport);
2984 return err;
2985 }
2986
2987 void
esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch * esw,struct mlx5_vport * vport)2988 esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw,
2989 struct mlx5_vport *vport)
2990 {
2991 esw_acl_egress_ofld_cleanup(vport);
2992 esw_acl_ingress_ofld_cleanup(esw, vport);
2993 }
2994
esw_create_uplink_offloads_acl_tables(struct mlx5_eswitch * esw)2995 static int esw_create_uplink_offloads_acl_tables(struct mlx5_eswitch *esw)
2996 {
2997 struct mlx5_vport *vport;
2998
2999 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
3000 if (IS_ERR(vport))
3001 return PTR_ERR(vport);
3002
3003 return esw_vport_create_offloads_acl_tables(esw, vport);
3004 }
3005
esw_destroy_uplink_offloads_acl_tables(struct mlx5_eswitch * esw)3006 static void esw_destroy_uplink_offloads_acl_tables(struct mlx5_eswitch *esw)
3007 {
3008 struct mlx5_vport *vport;
3009
3010 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
3011 if (IS_ERR(vport))
3012 return;
3013
3014 esw_vport_destroy_offloads_acl_tables(esw, vport);
3015 }
3016
mlx5_eswitch_reload_reps(struct mlx5_eswitch * esw)3017 int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw)
3018 {
3019 struct mlx5_eswitch_rep *rep;
3020 unsigned long i;
3021 int ret;
3022
3023 if (!esw || esw->mode != MLX5_ESWITCH_OFFLOADS)
3024 return 0;
3025
3026 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
3027 if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED)
3028 return 0;
3029
3030 ret = mlx5_esw_offloads_rep_load(esw, MLX5_VPORT_UPLINK);
3031 if (ret)
3032 return ret;
3033
3034 mlx5_esw_for_each_rep(esw, i, rep) {
3035 if (atomic_read(&rep->rep_data[REP_ETH].state) == REP_LOADED)
3036 mlx5_esw_offloads_rep_load(esw, rep->vport);
3037 }
3038
3039 return 0;
3040 }
3041
esw_offloads_steering_init(struct mlx5_eswitch * esw)3042 static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
3043 {
3044 struct mlx5_esw_indir_table *indir;
3045 int err;
3046
3047 memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
3048 mutex_init(&esw->fdb_table.offloads.vports.lock);
3049 hash_init(esw->fdb_table.offloads.vports.table);
3050 atomic64_set(&esw->user_count, 0);
3051
3052 indir = mlx5_esw_indir_table_init();
3053 if (IS_ERR(indir)) {
3054 err = PTR_ERR(indir);
3055 goto create_indir_err;
3056 }
3057 esw->fdb_table.offloads.indir = indir;
3058
3059 err = esw_create_uplink_offloads_acl_tables(esw);
3060 if (err)
3061 goto create_acl_err;
3062
3063 err = esw_create_offloads_table(esw);
3064 if (err)
3065 goto create_offloads_err;
3066
3067 err = esw_create_restore_table(esw);
3068 if (err)
3069 goto create_restore_err;
3070
3071 err = esw_create_offloads_fdb_tables(esw);
3072 if (err)
3073 goto create_fdb_err;
3074
3075 err = esw_create_vport_rx_group(esw);
3076 if (err)
3077 goto create_fg_err;
3078
3079 err = esw_create_vport_rx_drop_group(esw);
3080 if (err)
3081 goto create_rx_drop_fg_err;
3082
3083 err = esw_create_vport_rx_drop_rule(esw);
3084 if (err)
3085 goto create_rx_drop_rule_err;
3086
3087 return 0;
3088
3089 create_rx_drop_rule_err:
3090 esw_destroy_vport_rx_drop_group(esw);
3091 create_rx_drop_fg_err:
3092 esw_destroy_vport_rx_group(esw);
3093 create_fg_err:
3094 esw_destroy_offloads_fdb_tables(esw);
3095 create_fdb_err:
3096 esw_destroy_restore_table(esw);
3097 create_restore_err:
3098 esw_destroy_offloads_table(esw);
3099 create_offloads_err:
3100 esw_destroy_uplink_offloads_acl_tables(esw);
3101 create_acl_err:
3102 mlx5_esw_indir_table_destroy(esw->fdb_table.offloads.indir);
3103 create_indir_err:
3104 mutex_destroy(&esw->fdb_table.offloads.vports.lock);
3105 return err;
3106 }
3107
esw_offloads_steering_cleanup(struct mlx5_eswitch * esw)3108 static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
3109 {
3110 esw_destroy_vport_rx_drop_rule(esw);
3111 esw_destroy_vport_rx_drop_group(esw);
3112 esw_destroy_vport_rx_group(esw);
3113 esw_destroy_offloads_fdb_tables(esw);
3114 esw_destroy_restore_table(esw);
3115 esw_destroy_offloads_table(esw);
3116 esw_destroy_uplink_offloads_acl_tables(esw);
3117 mlx5_esw_indir_table_destroy(esw->fdb_table.offloads.indir);
3118 mutex_destroy(&esw->fdb_table.offloads.vports.lock);
3119 }
3120
3121 static void
esw_vfs_changed_event_handler(struct mlx5_eswitch * esw,const u32 * out)3122 esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
3123 {
3124 struct devlink *devlink;
3125 bool host_pf_disabled;
3126 u16 new_num_vfs;
3127
3128 new_num_vfs = MLX5_GET(query_esw_functions_out, out,
3129 host_params_context.host_num_of_vfs);
3130 host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
3131 host_params_context.host_pf_disabled);
3132
3133 if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
3134 return;
3135
3136 devlink = priv_to_devlink(esw->dev);
3137 devl_lock(devlink);
3138 /* Number of VFs can only change from "0 to x" or "x to 0". */
3139 if (esw->esw_funcs.num_vfs > 0) {
3140 mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
3141 } else {
3142 int err;
3143
3144 err = mlx5_eswitch_load_vf_vports(esw, new_num_vfs,
3145 MLX5_VPORT_UC_ADDR_CHANGE);
3146 if (err) {
3147 devl_unlock(devlink);
3148 return;
3149 }
3150 }
3151 esw->esw_funcs.num_vfs = new_num_vfs;
3152 devl_unlock(devlink);
3153 }
3154
esw_functions_changed_event_handler(struct work_struct * work)3155 static void esw_functions_changed_event_handler(struct work_struct *work)
3156 {
3157 struct mlx5_host_work *host_work;
3158 struct mlx5_eswitch *esw;
3159 const u32 *out;
3160
3161 host_work = container_of(work, struct mlx5_host_work, work);
3162 esw = host_work->esw;
3163
3164 out = mlx5_esw_query_functions(esw->dev);
3165 if (IS_ERR(out))
3166 goto out;
3167
3168 esw_vfs_changed_event_handler(esw, out);
3169 kvfree(out);
3170 out:
3171 kfree(host_work);
3172 }
3173
mlx5_esw_funcs_changed_handler(struct notifier_block * nb,unsigned long type,void * data)3174 int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data)
3175 {
3176 struct mlx5_esw_functions *esw_funcs;
3177 struct mlx5_host_work *host_work;
3178 struct mlx5_eswitch *esw;
3179
3180 host_work = kzalloc(sizeof(*host_work), GFP_ATOMIC);
3181 if (!host_work)
3182 return NOTIFY_DONE;
3183
3184 esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb);
3185 esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
3186
3187 host_work->esw = esw;
3188
3189 INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
3190 queue_work(esw->work_queue, &host_work->work);
3191
3192 return NOTIFY_OK;
3193 }
3194
mlx5_esw_host_number_init(struct mlx5_eswitch * esw)3195 static int mlx5_esw_host_number_init(struct mlx5_eswitch *esw)
3196 {
3197 const u32 *query_host_out;
3198
3199 if (!mlx5_core_is_ecpf_esw_manager(esw->dev))
3200 return 0;
3201
3202 query_host_out = mlx5_esw_query_functions(esw->dev);
3203 if (IS_ERR(query_host_out))
3204 return PTR_ERR(query_host_out);
3205
3206 /* Mark non local controller with non zero controller number. */
3207 esw->offloads.host_number = MLX5_GET(query_esw_functions_out, query_host_out,
3208 host_params_context.host_number);
3209 kvfree(query_host_out);
3210 return 0;
3211 }
3212
mlx5_esw_offloads_controller_valid(const struct mlx5_eswitch * esw,u32 controller)3213 bool mlx5_esw_offloads_controller_valid(const struct mlx5_eswitch *esw, u32 controller)
3214 {
3215 /* Local controller is always valid */
3216 if (controller == 0)
3217 return true;
3218
3219 if (!mlx5_core_is_ecpf_esw_manager(esw->dev))
3220 return false;
3221
3222 /* External host number starts with zero in device */
3223 return (controller == esw->offloads.host_number + 1);
3224 }
3225
esw_offloads_enable(struct mlx5_eswitch * esw)3226 int esw_offloads_enable(struct mlx5_eswitch *esw)
3227 {
3228 struct mapping_ctx *reg_c0_obj_pool;
3229 struct mlx5_vport *vport;
3230 unsigned long i;
3231 u64 mapping_id;
3232 int err;
3233
3234 mutex_init(&esw->offloads.termtbl_mutex);
3235 mlx5_rdma_enable_roce(esw->dev);
3236
3237 err = mlx5_esw_host_number_init(esw);
3238 if (err)
3239 goto err_metadata;
3240
3241 err = esw_offloads_metadata_init(esw);
3242 if (err)
3243 goto err_metadata;
3244
3245 err = esw_set_passing_vport_metadata(esw, true);
3246 if (err)
3247 goto err_vport_metadata;
3248
3249 mapping_id = mlx5_query_nic_system_image_guid(esw->dev);
3250
3251 reg_c0_obj_pool = mapping_create_for_id(mapping_id, MAPPING_TYPE_CHAIN,
3252 sizeof(struct mlx5_mapped_obj),
3253 ESW_REG_C0_USER_DATA_METADATA_MASK,
3254 true);
3255
3256 if (IS_ERR(reg_c0_obj_pool)) {
3257 err = PTR_ERR(reg_c0_obj_pool);
3258 goto err_pool;
3259 }
3260 esw->offloads.reg_c0_obj_pool = reg_c0_obj_pool;
3261
3262 err = esw_offloads_steering_init(esw);
3263 if (err)
3264 goto err_steering_init;
3265
3266 /* Representor will control the vport link state */
3267 mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs)
3268 vport->info.link_state = MLX5_VPORT_ADMIN_STATE_DOWN;
3269
3270 /* Uplink vport rep must load first. */
3271 err = esw_offloads_load_rep(esw, MLX5_VPORT_UPLINK);
3272 if (err)
3273 goto err_uplink;
3274
3275 err = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_VPORT_UC_ADDR_CHANGE);
3276 if (err)
3277 goto err_vports;
3278
3279 esw_offloads_devcom_init(esw);
3280
3281 return 0;
3282
3283 err_vports:
3284 esw_offloads_unload_rep(esw, MLX5_VPORT_UPLINK);
3285 err_uplink:
3286 esw_offloads_steering_cleanup(esw);
3287 err_steering_init:
3288 mapping_destroy(reg_c0_obj_pool);
3289 err_pool:
3290 esw_set_passing_vport_metadata(esw, false);
3291 err_vport_metadata:
3292 esw_offloads_metadata_uninit(esw);
3293 err_metadata:
3294 mlx5_rdma_disable_roce(esw->dev);
3295 mutex_destroy(&esw->offloads.termtbl_mutex);
3296 return err;
3297 }
3298
esw_offloads_stop(struct mlx5_eswitch * esw,struct netlink_ext_ack * extack)3299 static int esw_offloads_stop(struct mlx5_eswitch *esw,
3300 struct netlink_ext_ack *extack)
3301 {
3302 int err;
3303
3304 esw->mode = MLX5_ESWITCH_LEGACY;
3305
3306 /* If changing from switchdev to legacy mode without sriov enabled,
3307 * no need to create legacy fdb.
3308 */
3309 if (!mlx5_sriov_is_enabled(esw->dev))
3310 return 0;
3311
3312 err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
3313 if (err)
3314 NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
3315
3316 return err;
3317 }
3318
esw_offloads_disable(struct mlx5_eswitch * esw)3319 void esw_offloads_disable(struct mlx5_eswitch *esw)
3320 {
3321 esw_offloads_devcom_cleanup(esw);
3322 mlx5_eswitch_disable_pf_vf_vports(esw);
3323 esw_offloads_unload_rep(esw, MLX5_VPORT_UPLINK);
3324 esw_set_passing_vport_metadata(esw, false);
3325 esw_offloads_steering_cleanup(esw);
3326 mapping_destroy(esw->offloads.reg_c0_obj_pool);
3327 esw_offloads_metadata_uninit(esw);
3328 mlx5_rdma_disable_roce(esw->dev);
3329 mutex_destroy(&esw->offloads.termtbl_mutex);
3330 }
3331
esw_mode_from_devlink(u16 mode,u16 * mlx5_mode)3332 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
3333 {
3334 switch (mode) {
3335 case DEVLINK_ESWITCH_MODE_LEGACY:
3336 *mlx5_mode = MLX5_ESWITCH_LEGACY;
3337 break;
3338 case DEVLINK_ESWITCH_MODE_SWITCHDEV:
3339 *mlx5_mode = MLX5_ESWITCH_OFFLOADS;
3340 break;
3341 default:
3342 return -EINVAL;
3343 }
3344
3345 return 0;
3346 }
3347
esw_mode_to_devlink(u16 mlx5_mode,u16 * mode)3348 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
3349 {
3350 switch (mlx5_mode) {
3351 case MLX5_ESWITCH_LEGACY:
3352 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
3353 break;
3354 case MLX5_ESWITCH_OFFLOADS:
3355 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
3356 break;
3357 default:
3358 return -EINVAL;
3359 }
3360
3361 return 0;
3362 }
3363
esw_inline_mode_from_devlink(u8 mode,u8 * mlx5_mode)3364 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
3365 {
3366 switch (mode) {
3367 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
3368 *mlx5_mode = MLX5_INLINE_MODE_NONE;
3369 break;
3370 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
3371 *mlx5_mode = MLX5_INLINE_MODE_L2;
3372 break;
3373 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
3374 *mlx5_mode = MLX5_INLINE_MODE_IP;
3375 break;
3376 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
3377 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
3378 break;
3379 default:
3380 return -EINVAL;
3381 }
3382
3383 return 0;
3384 }
3385
esw_inline_mode_to_devlink(u8 mlx5_mode,u8 * mode)3386 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
3387 {
3388 switch (mlx5_mode) {
3389 case MLX5_INLINE_MODE_NONE:
3390 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
3391 break;
3392 case MLX5_INLINE_MODE_L2:
3393 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
3394 break;
3395 case MLX5_INLINE_MODE_IP:
3396 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
3397 break;
3398 case MLX5_INLINE_MODE_TCP_UDP:
3399 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
3400 break;
3401 default:
3402 return -EINVAL;
3403 }
3404
3405 return 0;
3406 }
3407
mlx5_devlink_eswitch_mode_set(struct devlink * devlink,u16 mode,struct netlink_ext_ack * extack)3408 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
3409 struct netlink_ext_ack *extack)
3410 {
3411 u16 cur_mlx5_mode, mlx5_mode = 0;
3412 struct mlx5_eswitch *esw;
3413 int err = 0;
3414
3415 esw = mlx5_devlink_eswitch_get(devlink);
3416 if (IS_ERR(esw))
3417 return PTR_ERR(esw);
3418
3419 if (esw_mode_from_devlink(mode, &mlx5_mode))
3420 return -EINVAL;
3421
3422 mlx5_lag_disable_change(esw->dev);
3423 err = mlx5_esw_try_lock(esw);
3424 if (err < 0) {
3425 NL_SET_ERR_MSG_MOD(extack, "Can't change mode, E-Switch is busy");
3426 goto enable_lag;
3427 }
3428 cur_mlx5_mode = err;
3429 err = 0;
3430
3431 if (cur_mlx5_mode == mlx5_mode)
3432 goto unlock;
3433
3434 mlx5_eswitch_disable_locked(esw);
3435 if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
3436 if (mlx5_devlink_trap_get_num_active(esw->dev)) {
3437 NL_SET_ERR_MSG_MOD(extack,
3438 "Can't change mode while devlink traps are active");
3439 err = -EOPNOTSUPP;
3440 goto unlock;
3441 }
3442 err = esw_offloads_start(esw, extack);
3443 } else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
3444 err = esw_offloads_stop(esw, extack);
3445 mlx5_rescan_drivers(esw->dev);
3446 } else {
3447 err = -EINVAL;
3448 }
3449
3450 unlock:
3451 mlx5_esw_unlock(esw);
3452 enable_lag:
3453 mlx5_lag_enable_change(esw->dev);
3454 return err;
3455 }
3456
mlx5_devlink_eswitch_mode_get(struct devlink * devlink,u16 * mode)3457 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
3458 {
3459 struct mlx5_eswitch *esw;
3460 int err;
3461
3462 esw = mlx5_devlink_eswitch_get(devlink);
3463 if (IS_ERR(esw))
3464 return PTR_ERR(esw);
3465
3466 down_read(&esw->mode_lock);
3467 err = esw_mode_to_devlink(esw->mode, mode);
3468 up_read(&esw->mode_lock);
3469 return err;
3470 }
3471
mlx5_esw_vports_inline_set(struct mlx5_eswitch * esw,u8 mlx5_mode,struct netlink_ext_ack * extack)3472 static int mlx5_esw_vports_inline_set(struct mlx5_eswitch *esw, u8 mlx5_mode,
3473 struct netlink_ext_ack *extack)
3474 {
3475 struct mlx5_core_dev *dev = esw->dev;
3476 struct mlx5_vport *vport;
3477 u16 err_vport_num = 0;
3478 unsigned long i;
3479 int err = 0;
3480
3481 mlx5_esw_for_each_host_func_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
3482 err = mlx5_modify_nic_vport_min_inline(dev, vport->vport, mlx5_mode);
3483 if (err) {
3484 err_vport_num = vport->vport;
3485 NL_SET_ERR_MSG_MOD(extack,
3486 "Failed to set min inline on vport");
3487 goto revert_inline_mode;
3488 }
3489 }
3490 return 0;
3491
3492 revert_inline_mode:
3493 mlx5_esw_for_each_host_func_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
3494 if (vport->vport == err_vport_num)
3495 break;
3496 mlx5_modify_nic_vport_min_inline(dev,
3497 vport->vport,
3498 esw->offloads.inline_mode);
3499 }
3500 return err;
3501 }
3502
mlx5_devlink_eswitch_inline_mode_set(struct devlink * devlink,u8 mode,struct netlink_ext_ack * extack)3503 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
3504 struct netlink_ext_ack *extack)
3505 {
3506 struct mlx5_core_dev *dev = devlink_priv(devlink);
3507 struct mlx5_eswitch *esw;
3508 u8 mlx5_mode;
3509 int err;
3510
3511 esw = mlx5_devlink_eswitch_get(devlink);
3512 if (IS_ERR(esw))
3513 return PTR_ERR(esw);
3514
3515 down_write(&esw->mode_lock);
3516
3517 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
3518 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
3519 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE) {
3520 err = 0;
3521 goto out;
3522 }
3523
3524 fallthrough;
3525 case MLX5_CAP_INLINE_MODE_L2:
3526 NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
3527 err = -EOPNOTSUPP;
3528 goto out;
3529 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
3530 break;
3531 }
3532
3533 if (atomic64_read(&esw->offloads.num_flows) > 0) {
3534 NL_SET_ERR_MSG_MOD(extack,
3535 "Can't set inline mode when flows are configured");
3536 err = -EOPNOTSUPP;
3537 goto out;
3538 }
3539
3540 err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
3541 if (err)
3542 goto out;
3543
3544 err = mlx5_esw_vports_inline_set(esw, mlx5_mode, extack);
3545 if (err)
3546 goto out;
3547
3548 esw->offloads.inline_mode = mlx5_mode;
3549 up_write(&esw->mode_lock);
3550 return 0;
3551
3552 out:
3553 up_write(&esw->mode_lock);
3554 return err;
3555 }
3556
mlx5_devlink_eswitch_inline_mode_get(struct devlink * devlink,u8 * mode)3557 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
3558 {
3559 struct mlx5_eswitch *esw;
3560 int err;
3561
3562 esw = mlx5_devlink_eswitch_get(devlink);
3563 if (IS_ERR(esw))
3564 return PTR_ERR(esw);
3565
3566 down_read(&esw->mode_lock);
3567 err = esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
3568 up_read(&esw->mode_lock);
3569 return err;
3570 }
3571
mlx5_devlink_eswitch_encap_mode_set(struct devlink * devlink,enum devlink_eswitch_encap_mode encap,struct netlink_ext_ack * extack)3572 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
3573 enum devlink_eswitch_encap_mode encap,
3574 struct netlink_ext_ack *extack)
3575 {
3576 struct mlx5_core_dev *dev = devlink_priv(devlink);
3577 struct mlx5_eswitch *esw;
3578 int err = 0;
3579
3580 esw = mlx5_devlink_eswitch_get(devlink);
3581 if (IS_ERR(esw))
3582 return PTR_ERR(esw);
3583
3584 down_write(&esw->mode_lock);
3585
3586 if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
3587 (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
3588 !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))) {
3589 err = -EOPNOTSUPP;
3590 goto unlock;
3591 }
3592
3593 if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC) {
3594 err = -EOPNOTSUPP;
3595 goto unlock;
3596 }
3597
3598 if (esw->mode == MLX5_ESWITCH_LEGACY) {
3599 esw->offloads.encap = encap;
3600 goto unlock;
3601 }
3602
3603 if (esw->offloads.encap == encap)
3604 goto unlock;
3605
3606 if (atomic64_read(&esw->offloads.num_flows) > 0) {
3607 NL_SET_ERR_MSG_MOD(extack,
3608 "Can't set encapsulation when flows are configured");
3609 err = -EOPNOTSUPP;
3610 goto unlock;
3611 }
3612
3613 esw_destroy_offloads_fdb_tables(esw);
3614
3615 esw->offloads.encap = encap;
3616
3617 err = esw_create_offloads_fdb_tables(esw);
3618
3619 if (err) {
3620 NL_SET_ERR_MSG_MOD(extack,
3621 "Failed re-creating fast FDB table");
3622 esw->offloads.encap = !encap;
3623 (void)esw_create_offloads_fdb_tables(esw);
3624 }
3625
3626 unlock:
3627 up_write(&esw->mode_lock);
3628 return err;
3629 }
3630
mlx5_devlink_eswitch_encap_mode_get(struct devlink * devlink,enum devlink_eswitch_encap_mode * encap)3631 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
3632 enum devlink_eswitch_encap_mode *encap)
3633 {
3634 struct mlx5_eswitch *esw;
3635
3636 esw = mlx5_devlink_eswitch_get(devlink);
3637 if (IS_ERR(esw))
3638 return PTR_ERR(esw);
3639
3640 down_read(&esw->mode_lock);
3641 *encap = esw->offloads.encap;
3642 up_read(&esw->mode_lock);
3643 return 0;
3644 }
3645
3646 static bool
mlx5_eswitch_vport_has_rep(const struct mlx5_eswitch * esw,u16 vport_num)3647 mlx5_eswitch_vport_has_rep(const struct mlx5_eswitch *esw, u16 vport_num)
3648 {
3649 /* Currently, only ECPF based device has representor for host PF. */
3650 if (vport_num == MLX5_VPORT_PF &&
3651 !mlx5_core_is_ecpf_esw_manager(esw->dev))
3652 return false;
3653
3654 if (vport_num == MLX5_VPORT_ECPF &&
3655 !mlx5_ecpf_vport_exists(esw->dev))
3656 return false;
3657
3658 return true;
3659 }
3660
mlx5_eswitch_register_vport_reps(struct mlx5_eswitch * esw,const struct mlx5_eswitch_rep_ops * ops,u8 rep_type)3661 void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw,
3662 const struct mlx5_eswitch_rep_ops *ops,
3663 u8 rep_type)
3664 {
3665 struct mlx5_eswitch_rep_data *rep_data;
3666 struct mlx5_eswitch_rep *rep;
3667 unsigned long i;
3668
3669 esw->offloads.rep_ops[rep_type] = ops;
3670 mlx5_esw_for_each_rep(esw, i, rep) {
3671 if (likely(mlx5_eswitch_vport_has_rep(esw, rep->vport))) {
3672 rep->esw = esw;
3673 rep_data = &rep->rep_data[rep_type];
3674 atomic_set(&rep_data->state, REP_REGISTERED);
3675 }
3676 }
3677 }
3678 EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);
3679
mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch * esw,u8 rep_type)3680 void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type)
3681 {
3682 struct mlx5_eswitch_rep *rep;
3683 unsigned long i;
3684
3685 if (esw->mode == MLX5_ESWITCH_OFFLOADS)
3686 __unload_reps_all_vport(esw, rep_type);
3687
3688 mlx5_esw_for_each_rep(esw, i, rep)
3689 atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
3690 }
3691 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
3692
mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch * esw,u8 rep_type)3693 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
3694 {
3695 struct mlx5_eswitch_rep *rep;
3696
3697 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
3698 return rep->rep_data[rep_type].priv;
3699 }
3700
mlx5_eswitch_get_proto_dev(struct mlx5_eswitch * esw,u16 vport,u8 rep_type)3701 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
3702 u16 vport,
3703 u8 rep_type)
3704 {
3705 struct mlx5_eswitch_rep *rep;
3706
3707 rep = mlx5_eswitch_get_rep(esw, vport);
3708
3709 if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
3710 esw->offloads.rep_ops[rep_type]->get_proto_dev)
3711 return esw->offloads.rep_ops[rep_type]->get_proto_dev(rep);
3712 return NULL;
3713 }
3714 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
3715
mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch * esw,u8 rep_type)3716 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
3717 {
3718 return mlx5_eswitch_get_proto_dev(esw, MLX5_VPORT_UPLINK, rep_type);
3719 }
3720 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
3721
mlx5_eswitch_vport_rep(struct mlx5_eswitch * esw,u16 vport)3722 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
3723 u16 vport)
3724 {
3725 return mlx5_eswitch_get_rep(esw, vport);
3726 }
3727 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);
3728
mlx5_eswitch_reg_c1_loopback_enabled(const struct mlx5_eswitch * esw)3729 bool mlx5_eswitch_reg_c1_loopback_enabled(const struct mlx5_eswitch *esw)
3730 {
3731 return !!(esw->flags & MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED);
3732 }
3733 EXPORT_SYMBOL(mlx5_eswitch_reg_c1_loopback_enabled);
3734
mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch * esw)3735 bool mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch *esw)
3736 {
3737 return !!(esw->flags & MLX5_ESWITCH_VPORT_MATCH_METADATA);
3738 }
3739 EXPORT_SYMBOL(mlx5_eswitch_vport_match_metadata_enabled);
3740
mlx5_eswitch_get_vport_metadata_for_match(struct mlx5_eswitch * esw,u16 vport_num)3741 u32 mlx5_eswitch_get_vport_metadata_for_match(struct mlx5_eswitch *esw,
3742 u16 vport_num)
3743 {
3744 struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
3745
3746 if (WARN_ON_ONCE(IS_ERR(vport)))
3747 return 0;
3748
3749 return vport->metadata << (32 - ESW_SOURCE_PORT_METADATA_BITS);
3750 }
3751 EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match);
3752
mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch * esw,struct devlink_port * dl_port,u16 vport_num,u32 controller,u32 sfnum)3753 int mlx5_esw_offloads_sf_vport_enable(struct mlx5_eswitch *esw, struct devlink_port *dl_port,
3754 u16 vport_num, u32 controller, u32 sfnum)
3755 {
3756 int err;
3757
3758 err = mlx5_esw_vport_enable(esw, vport_num, MLX5_VPORT_UC_ADDR_CHANGE);
3759 if (err)
3760 return err;
3761
3762 err = mlx5_esw_devlink_sf_port_register(esw, dl_port, vport_num, controller, sfnum);
3763 if (err)
3764 goto devlink_err;
3765
3766 mlx5_esw_vport_debugfs_create(esw, vport_num, true, sfnum);
3767 err = mlx5_esw_offloads_rep_load(esw, vport_num);
3768 if (err)
3769 goto rep_err;
3770 return 0;
3771
3772 rep_err:
3773 mlx5_esw_vport_debugfs_destroy(esw, vport_num);
3774 mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
3775 devlink_err:
3776 mlx5_esw_vport_disable(esw, vport_num);
3777 return err;
3778 }
3779
mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch * esw,u16 vport_num)3780 void mlx5_esw_offloads_sf_vport_disable(struct mlx5_eswitch *esw, u16 vport_num)
3781 {
3782 mlx5_esw_offloads_rep_unload(esw, vport_num);
3783 mlx5_esw_vport_debugfs_destroy(esw, vport_num);
3784 mlx5_esw_devlink_sf_port_unregister(esw, vport_num);
3785 mlx5_esw_vport_disable(esw, vport_num);
3786 }
3787
mlx5_esw_query_vport_vhca_id(struct mlx5_eswitch * esw,u16 vport_num,u16 * vhca_id)3788 static int mlx5_esw_query_vport_vhca_id(struct mlx5_eswitch *esw, u16 vport_num, u16 *vhca_id)
3789 {
3790 int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
3791 void *query_ctx;
3792 void *hca_caps;
3793 int err;
3794
3795 *vhca_id = 0;
3796 if (mlx5_esw_is_manager_vport(esw, vport_num) ||
3797 !MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
3798 return -EPERM;
3799
3800 query_ctx = kzalloc(query_out_sz, GFP_KERNEL);
3801 if (!query_ctx)
3802 return -ENOMEM;
3803
3804 err = mlx5_vport_get_other_func_general_cap(esw->dev, vport_num, query_ctx);
3805 if (err)
3806 goto out_free;
3807
3808 hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
3809 *vhca_id = MLX5_GET(cmd_hca_cap, hca_caps, vhca_id);
3810
3811 out_free:
3812 kfree(query_ctx);
3813 return err;
3814 }
3815
mlx5_esw_vport_vhca_id_set(struct mlx5_eswitch * esw,u16 vport_num)3816 int mlx5_esw_vport_vhca_id_set(struct mlx5_eswitch *esw, u16 vport_num)
3817 {
3818 u16 *old_entry, *vhca_map_entry, vhca_id;
3819 int err;
3820
3821 err = mlx5_esw_query_vport_vhca_id(esw, vport_num, &vhca_id);
3822 if (err) {
3823 esw_warn(esw->dev, "Getting vhca_id for vport failed (vport=%u,err=%d)\n",
3824 vport_num, err);
3825 return err;
3826 }
3827
3828 vhca_map_entry = kmalloc(sizeof(*vhca_map_entry), GFP_KERNEL);
3829 if (!vhca_map_entry)
3830 return -ENOMEM;
3831
3832 *vhca_map_entry = vport_num;
3833 old_entry = xa_store(&esw->offloads.vhca_map, vhca_id, vhca_map_entry, GFP_KERNEL);
3834 if (xa_is_err(old_entry)) {
3835 kfree(vhca_map_entry);
3836 return xa_err(old_entry);
3837 }
3838 kfree(old_entry);
3839 return 0;
3840 }
3841
mlx5_esw_vport_vhca_id_clear(struct mlx5_eswitch * esw,u16 vport_num)3842 void mlx5_esw_vport_vhca_id_clear(struct mlx5_eswitch *esw, u16 vport_num)
3843 {
3844 u16 *vhca_map_entry, vhca_id;
3845 int err;
3846
3847 err = mlx5_esw_query_vport_vhca_id(esw, vport_num, &vhca_id);
3848 if (err)
3849 esw_warn(esw->dev, "Getting vhca_id for vport failed (vport=%hu,err=%d)\n",
3850 vport_num, err);
3851
3852 vhca_map_entry = xa_erase(&esw->offloads.vhca_map, vhca_id);
3853 kfree(vhca_map_entry);
3854 }
3855
mlx5_eswitch_vhca_id_to_vport(struct mlx5_eswitch * esw,u16 vhca_id,u16 * vport_num)3856 int mlx5_eswitch_vhca_id_to_vport(struct mlx5_eswitch *esw, u16 vhca_id, u16 *vport_num)
3857 {
3858 u16 *res = xa_load(&esw->offloads.vhca_map, vhca_id);
3859
3860 if (!res)
3861 return -ENOENT;
3862
3863 *vport_num = *res;
3864 return 0;
3865 }
3866
mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch * esw,u16 vport_num)3867 u32 mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch *esw,
3868 u16 vport_num)
3869 {
3870 struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
3871
3872 if (WARN_ON_ONCE(IS_ERR(vport)))
3873 return 0;
3874
3875 return vport->metadata;
3876 }
3877 EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_set);
3878
3879 static bool
is_port_function_supported(struct mlx5_eswitch * esw,u16 vport_num)3880 is_port_function_supported(struct mlx5_eswitch *esw, u16 vport_num)
3881 {
3882 return vport_num == MLX5_VPORT_PF ||
3883 mlx5_eswitch_is_vf_vport(esw, vport_num) ||
3884 mlx5_esw_is_sf_vport(esw, vport_num);
3885 }
3886
mlx5_devlink_port_function_hw_addr_get(struct devlink_port * port,u8 * hw_addr,int * hw_addr_len,struct netlink_ext_ack * extack)3887 int mlx5_devlink_port_function_hw_addr_get(struct devlink_port *port,
3888 u8 *hw_addr, int *hw_addr_len,
3889 struct netlink_ext_ack *extack)
3890 {
3891 struct mlx5_eswitch *esw;
3892 struct mlx5_vport *vport;
3893 u16 vport_num;
3894
3895 esw = mlx5_devlink_eswitch_get(port->devlink);
3896 if (IS_ERR(esw))
3897 return PTR_ERR(esw);
3898
3899 vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
3900 if (!is_port_function_supported(esw, vport_num))
3901 return -EOPNOTSUPP;
3902
3903 vport = mlx5_eswitch_get_vport(esw, vport_num);
3904 if (IS_ERR(vport)) {
3905 NL_SET_ERR_MSG_MOD(extack, "Invalid port");
3906 return PTR_ERR(vport);
3907 }
3908
3909 mutex_lock(&esw->state_lock);
3910 ether_addr_copy(hw_addr, vport->info.mac);
3911 *hw_addr_len = ETH_ALEN;
3912 mutex_unlock(&esw->state_lock);
3913 return 0;
3914 }
3915
mlx5_devlink_port_function_hw_addr_set(struct devlink_port * port,const u8 * hw_addr,int hw_addr_len,struct netlink_ext_ack * extack)3916 int mlx5_devlink_port_function_hw_addr_set(struct devlink_port *port,
3917 const u8 *hw_addr, int hw_addr_len,
3918 struct netlink_ext_ack *extack)
3919 {
3920 struct mlx5_eswitch *esw;
3921 u16 vport_num;
3922
3923 esw = mlx5_devlink_eswitch_get(port->devlink);
3924 if (IS_ERR(esw)) {
3925 NL_SET_ERR_MSG_MOD(extack, "Eswitch doesn't support set hw_addr");
3926 return PTR_ERR(esw);
3927 }
3928
3929 vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
3930 if (!is_port_function_supported(esw, vport_num)) {
3931 NL_SET_ERR_MSG_MOD(extack, "Port doesn't support set hw_addr");
3932 return -EINVAL;
3933 }
3934
3935 return mlx5_eswitch_set_vport_mac(esw, vport_num, hw_addr);
3936 }
3937
3938 static struct mlx5_vport *
mlx5_devlink_port_fn_get_vport(struct devlink_port * port,struct mlx5_eswitch * esw)3939 mlx5_devlink_port_fn_get_vport(struct devlink_port *port, struct mlx5_eswitch *esw)
3940 {
3941 u16 vport_num;
3942
3943 if (!MLX5_CAP_GEN(esw->dev, vhca_resource_manager))
3944 return ERR_PTR(-EOPNOTSUPP);
3945
3946 vport_num = mlx5_esw_devlink_port_index_to_vport_num(port->index);
3947 if (!is_port_function_supported(esw, vport_num))
3948 return ERR_PTR(-EOPNOTSUPP);
3949
3950 return mlx5_eswitch_get_vport(esw, vport_num);
3951 }
3952
mlx5_devlink_port_fn_migratable_get(struct devlink_port * port,bool * is_enabled,struct netlink_ext_ack * extack)3953 int mlx5_devlink_port_fn_migratable_get(struct devlink_port *port, bool *is_enabled,
3954 struct netlink_ext_ack *extack)
3955 {
3956 struct mlx5_eswitch *esw;
3957 struct mlx5_vport *vport;
3958 int err = -EOPNOTSUPP;
3959
3960 esw = mlx5_devlink_eswitch_get(port->devlink);
3961 if (IS_ERR(esw))
3962 return PTR_ERR(esw);
3963
3964 if (!MLX5_CAP_GEN(esw->dev, migration)) {
3965 NL_SET_ERR_MSG_MOD(extack, "Device doesn't support migration");
3966 return err;
3967 }
3968
3969 vport = mlx5_devlink_port_fn_get_vport(port, esw);
3970 if (IS_ERR(vport)) {
3971 NL_SET_ERR_MSG_MOD(extack, "Invalid port");
3972 return PTR_ERR(vport);
3973 }
3974
3975 mutex_lock(&esw->state_lock);
3976 if (vport->enabled) {
3977 *is_enabled = vport->info.mig_enabled;
3978 err = 0;
3979 }
3980 mutex_unlock(&esw->state_lock);
3981 return err;
3982 }
3983
mlx5_devlink_port_fn_migratable_set(struct devlink_port * port,bool enable,struct netlink_ext_ack * extack)3984 int mlx5_devlink_port_fn_migratable_set(struct devlink_port *port, bool enable,
3985 struct netlink_ext_ack *extack)
3986 {
3987 int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
3988 struct mlx5_eswitch *esw;
3989 struct mlx5_vport *vport;
3990 void *query_ctx;
3991 void *hca_caps;
3992 int err = -EOPNOTSUPP;
3993
3994 esw = mlx5_devlink_eswitch_get(port->devlink);
3995 if (IS_ERR(esw))
3996 return PTR_ERR(esw);
3997
3998 if (!MLX5_CAP_GEN(esw->dev, migration)) {
3999 NL_SET_ERR_MSG_MOD(extack, "Device doesn't support migration");
4000 return err;
4001 }
4002
4003 vport = mlx5_devlink_port_fn_get_vport(port, esw);
4004 if (IS_ERR(vport)) {
4005 NL_SET_ERR_MSG_MOD(extack, "Invalid port");
4006 return PTR_ERR(vport);
4007 }
4008
4009 mutex_lock(&esw->state_lock);
4010 if (!vport->enabled) {
4011 NL_SET_ERR_MSG_MOD(extack, "Eswitch vport is disabled");
4012 goto out;
4013 }
4014
4015 if (vport->info.mig_enabled == enable) {
4016 err = 0;
4017 goto out;
4018 }
4019
4020 query_ctx = kzalloc(query_out_sz, GFP_KERNEL);
4021 if (!query_ctx) {
4022 err = -ENOMEM;
4023 goto out;
4024 }
4025
4026 err = mlx5_vport_get_other_func_cap(esw->dev, vport->vport, query_ctx,
4027 MLX5_CAP_GENERAL_2);
4028 if (err) {
4029 NL_SET_ERR_MSG_MOD(extack, "Failed getting HCA caps");
4030 goto out_free;
4031 }
4032
4033 hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
4034 MLX5_SET(cmd_hca_cap_2, hca_caps, migratable, 1);
4035
4036 err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport->vport,
4037 MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE2);
4038 if (err) {
4039 NL_SET_ERR_MSG_MOD(extack, "Failed setting HCA migratable cap");
4040 goto out_free;
4041 }
4042
4043 vport->info.mig_enabled = enable;
4044
4045 out_free:
4046 kfree(query_ctx);
4047 out:
4048 mutex_unlock(&esw->state_lock);
4049 return err;
4050 }
4051
mlx5_devlink_port_fn_roce_get(struct devlink_port * port,bool * is_enabled,struct netlink_ext_ack * extack)4052 int mlx5_devlink_port_fn_roce_get(struct devlink_port *port, bool *is_enabled,
4053 struct netlink_ext_ack *extack)
4054 {
4055 struct mlx5_eswitch *esw;
4056 struct mlx5_vport *vport;
4057 int err = -EOPNOTSUPP;
4058
4059 esw = mlx5_devlink_eswitch_get(port->devlink);
4060 if (IS_ERR(esw))
4061 return PTR_ERR(esw);
4062
4063 vport = mlx5_devlink_port_fn_get_vport(port, esw);
4064 if (IS_ERR(vport)) {
4065 NL_SET_ERR_MSG_MOD(extack, "Invalid port");
4066 return PTR_ERR(vport);
4067 }
4068
4069 mutex_lock(&esw->state_lock);
4070 if (vport->enabled) {
4071 *is_enabled = vport->info.roce_enabled;
4072 err = 0;
4073 }
4074 mutex_unlock(&esw->state_lock);
4075 return err;
4076 }
4077
mlx5_devlink_port_fn_roce_set(struct devlink_port * port,bool enable,struct netlink_ext_ack * extack)4078 int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable,
4079 struct netlink_ext_ack *extack)
4080 {
4081 int query_out_sz = MLX5_ST_SZ_BYTES(query_hca_cap_out);
4082 struct mlx5_eswitch *esw;
4083 struct mlx5_vport *vport;
4084 int err = -EOPNOTSUPP;
4085 void *query_ctx;
4086 void *hca_caps;
4087 u16 vport_num;
4088
4089 esw = mlx5_devlink_eswitch_get(port->devlink);
4090 if (IS_ERR(esw))
4091 return PTR_ERR(esw);
4092
4093 vport = mlx5_devlink_port_fn_get_vport(port, esw);
4094 if (IS_ERR(vport)) {
4095 NL_SET_ERR_MSG_MOD(extack, "Invalid port");
4096 return PTR_ERR(vport);
4097 }
4098 vport_num = vport->vport;
4099
4100 mutex_lock(&esw->state_lock);
4101 if (!vport->enabled) {
4102 NL_SET_ERR_MSG_MOD(extack, "Eswitch vport is disabled");
4103 goto out;
4104 }
4105
4106 if (vport->info.roce_enabled == enable) {
4107 err = 0;
4108 goto out;
4109 }
4110
4111 query_ctx = kzalloc(query_out_sz, GFP_KERNEL);
4112 if (!query_ctx) {
4113 err = -ENOMEM;
4114 goto out;
4115 }
4116
4117 err = mlx5_vport_get_other_func_cap(esw->dev, vport_num, query_ctx,
4118 MLX5_CAP_GENERAL);
4119 if (err) {
4120 NL_SET_ERR_MSG_MOD(extack, "Failed getting HCA caps");
4121 goto out_free;
4122 }
4123
4124 hca_caps = MLX5_ADDR_OF(query_hca_cap_out, query_ctx, capability);
4125 MLX5_SET(cmd_hca_cap, hca_caps, roce, enable);
4126
4127 err = mlx5_vport_set_other_func_cap(esw->dev, hca_caps, vport_num,
4128 MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE);
4129 if (err) {
4130 NL_SET_ERR_MSG_MOD(extack, "Failed setting HCA roce cap");
4131 goto out_free;
4132 }
4133
4134 vport->info.roce_enabled = enable;
4135
4136 out_free:
4137 kfree(query_ctx);
4138 out:
4139 mutex_unlock(&esw->state_lock);
4140 return err;
4141 }
4142