]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
net/mlx5: E-Switch prepare functions change handler to be modular
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch_offloads.c
CommitLineData
69697b6e
OG
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/mlx5/driver.h>
35#include <linux/mlx5/mlx5_ifc.h>
36#include <linux/mlx5/vport.h>
37#include <linux/mlx5/fs.h>
38#include "mlx5_core.h"
39#include "eswitch.h"
80f09dfc 40#include "rdma.h"
e52c2802
PB
41#include "en.h"
42#include "fs_core.h"
ac004b83 43#include "lib/devcom.h"
a3888f33 44#include "lib/eq.h"
69697b6e 45
cd7e4186
BW
46/* There are two match-all miss flows, one for unicast dst mac and
47 * one for multicast.
48 */
49#define MLX5_ESW_MISS_FLOWS (2)
50
e52c2802
PB
51#define fdb_prio_table(esw, chain, prio, level) \
52 (esw)->fdb_table.offloads.fdb_prio[(chain)][(prio)][(level)]
53
c9b99abc
BW
54#define UPLINK_REP_INDEX 0
55
879c8f84
BW
56static struct mlx5_eswitch_rep *mlx5_eswitch_get_rep(struct mlx5_eswitch *esw,
57 u16 vport_num)
58{
5ae51620 59 u16 idx = mlx5_eswitch_vport_num_to_index(esw, vport_num);
879c8f84
BW
60
61 WARN_ON(idx > esw->total_vports - 1);
62 return &esw->offloads.vport_reps[idx];
63}
64
e52c2802
PB
65static struct mlx5_flow_table *
66esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
67static void
68esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
69
70bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw)
71{
72 return (!!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED));
73}
74
75u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw)
76{
77 if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
78 return FDB_MAX_CHAIN;
79
80 return 0;
81}
82
83u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw)
84{
85 if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
86 return FDB_MAX_PRIO;
87
bf07aa73 88 return 1;
e52c2802
PB
89}
90
c01cfd0f
JL
91static void
92mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
93 struct mlx5_flow_spec *spec,
94 struct mlx5_esw_flow_attr *attr)
95{
96 void *misc2;
97 void *misc;
98
99 /* Use metadata matching because vport is not represented by single
100 * VHCA in dual-port RoCE mode, and matching on source vport may fail.
101 */
102 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
103 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
104 MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
105 mlx5_eswitch_get_vport_metadata_for_match(attr->in_mdev->priv.eswitch,
106 attr->in_rep->vport));
107
108 misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
109 MLX5_SET_TO_ONES(fte_match_set_misc2, misc2, metadata_reg_c_0);
110
111 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
112 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
113 if (memchr_inv(misc, 0, MLX5_ST_SZ_BYTES(fte_match_set_misc)))
114 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
115 } else {
116 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
117 MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
118
119 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
120 MLX5_SET(fte_match_set_misc, misc,
121 source_eswitch_owner_vhca_id,
122 MLX5_CAP_GEN(attr->in_mdev, vhca_id));
123
124 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
125 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
126 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
127 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
128 source_eswitch_owner_vhca_id);
129
130 spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
131 }
132
133 if (MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) &&
134 attr->in_rep->vport == MLX5_VPORT_UPLINK)
135 spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
136}
137
74491de9 138struct mlx5_flow_handle *
3d80d1a2
OG
139mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
140 struct mlx5_flow_spec *spec,
776b12b6 141 struct mlx5_esw_flow_attr *attr)
3d80d1a2 142{
592d3651 143 struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
42f7ad67 144 struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
e85e02ba 145 bool split = !!(attr->split_count);
74491de9 146 struct mlx5_flow_handle *rule;
e52c2802 147 struct mlx5_flow_table *fdb;
592d3651 148 int j, i = 0;
3d80d1a2 149
f6455de0 150 if (esw->mode != MLX5_ESWITCH_OFFLOADS)
3d80d1a2
OG
151 return ERR_PTR(-EOPNOTSUPP);
152
6acfbf38
OG
153 flow_act.action = attr->action;
154 /* if per flow vlan pop/push is emulated, don't set that into the firmware */
cc495188 155 if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
6acfbf38
OG
156 flow_act.action &= ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
157 MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
158 else if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
1482bd3d
JL
159 flow_act.vlan[0].ethtype = ntohs(attr->vlan_proto[0]);
160 flow_act.vlan[0].vid = attr->vlan_vid[0];
161 flow_act.vlan[0].prio = attr->vlan_prio[0];
cc495188
JL
162 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
163 flow_act.vlan[1].ethtype = ntohs(attr->vlan_proto[1]);
164 flow_act.vlan[1].vid = attr->vlan_vid[1];
165 flow_act.vlan[1].prio = attr->vlan_prio[1];
166 }
6acfbf38 167 }
776b12b6 168
66958ed9 169 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
e52c2802
PB
170 if (attr->dest_chain) {
171 struct mlx5_flow_table *ft;
172
173 ft = esw_get_prio_table(esw, attr->dest_chain, 1, 0);
174 if (IS_ERR(ft)) {
175 rule = ERR_CAST(ft);
176 goto err_create_goto_table;
177 }
178
179 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
180 dest[i].ft = ft;
592d3651 181 i++;
e52c2802 182 } else {
e85e02ba 183 for (j = attr->split_count; j < attr->out_count; j++) {
e52c2802 184 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
df65a573 185 dest[i].vport.num = attr->dests[j].rep->vport;
e52c2802 186 dest[i].vport.vhca_id =
df65a573 187 MLX5_CAP_GEN(attr->dests[j].mdev, vhca_id);
aa39c2c0
EB
188 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
189 dest[i].vport.flags |=
190 MLX5_FLOW_DEST_VPORT_VHCA_ID;
f493f155
EB
191 if (attr->dests[j].flags & MLX5_ESW_DEST_ENCAP) {
192 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
8c4dc42b 193 flow_act.reformat_id = attr->dests[j].encap_id;
a18e879d 194 dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
8c4dc42b
EB
195 dest[i].vport.reformat_id =
196 attr->dests[j].encap_id;
f493f155 197 }
e52c2802
PB
198 i++;
199 }
56e858df 200 }
e37a79e5 201 }
66958ed9 202 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
e37a79e5 203 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
171c7625 204 dest[i].counter_id = mlx5_fc_id(attr->counter);
e37a79e5 205 i++;
3d80d1a2
OG
206 }
207
c01cfd0f 208 mlx5_eswitch_set_rule_source_port(esw, spec, attr);
3d80d1a2 209
6363651d
OG
210 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
211 if (attr->tunnel_match_level != MLX5_MATCH_NONE)
212 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
213 if (attr->match_level != MLX5_MATCH_NONE)
214 spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
215 } else if (attr->match_level != MLX5_MATCH_NONE) {
216 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
217 }
3d80d1a2 218
aa24670e 219 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
d7e75a32
OG
220 flow_act.modify_id = attr->mod_hdr_id;
221
e85e02ba 222 fdb = esw_get_prio_table(esw, attr->chain, attr->prio, !!split);
e52c2802
PB
223 if (IS_ERR(fdb)) {
224 rule = ERR_CAST(fdb);
225 goto err_esw_get;
226 }
227
228 rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
3d80d1a2 229 if (IS_ERR(rule))
e52c2802 230 goto err_add_rule;
375f51e2
RD
231 else
232 esw->offloads.num_flows++;
3d80d1a2 233
e52c2802
PB
234 return rule;
235
236err_add_rule:
e85e02ba 237 esw_put_prio_table(esw, attr->chain, attr->prio, !!split);
e52c2802
PB
238err_esw_get:
239 if (attr->dest_chain)
240 esw_put_prio_table(esw, attr->dest_chain, 1, 0);
241err_create_goto_table:
aa0cbbae 242 return rule;
3d80d1a2
OG
243}
244
e4ad91f2
CM
245struct mlx5_flow_handle *
246mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
247 struct mlx5_flow_spec *spec,
248 struct mlx5_esw_flow_attr *attr)
249{
250 struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
42f7ad67 251 struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
e52c2802
PB
252 struct mlx5_flow_table *fast_fdb;
253 struct mlx5_flow_table *fwd_fdb;
e4ad91f2 254 struct mlx5_flow_handle *rule;
e4ad91f2
CM
255 int i;
256
e52c2802
PB
257 fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0);
258 if (IS_ERR(fast_fdb)) {
259 rule = ERR_CAST(fast_fdb);
260 goto err_get_fast;
261 }
262
263 fwd_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 1);
264 if (IS_ERR(fwd_fdb)) {
265 rule = ERR_CAST(fwd_fdb);
266 goto err_get_fwd;
267 }
268
e4ad91f2 269 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
e85e02ba 270 for (i = 0; i < attr->split_count; i++) {
e4ad91f2 271 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
df65a573 272 dest[i].vport.num = attr->dests[i].rep->vport;
e4ad91f2 273 dest[i].vport.vhca_id =
df65a573 274 MLX5_CAP_GEN(attr->dests[i].mdev, vhca_id);
aa39c2c0
EB
275 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
276 dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
1cc26d74
EB
277 if (attr->dests[i].flags & MLX5_ESW_DEST_ENCAP) {
278 dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
8c4dc42b 279 dest[i].vport.reformat_id = attr->dests[i].encap_id;
1cc26d74 280 }
e4ad91f2
CM
281 }
282 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
e52c2802 283 dest[i].ft = fwd_fdb,
e4ad91f2
CM
284 i++;
285
c01cfd0f 286 mlx5_eswitch_set_rule_source_port(esw, spec, attr);
e4ad91f2 287
c01cfd0f
JL
288 if (attr->match_level != MLX5_MATCH_NONE)
289 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
e4ad91f2 290
e52c2802 291 rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
e4ad91f2 292
e52c2802
PB
293 if (IS_ERR(rule))
294 goto add_err;
e4ad91f2 295
e52c2802
PB
296 esw->offloads.num_flows++;
297
298 return rule;
299add_err:
300 esw_put_prio_table(esw, attr->chain, attr->prio, 1);
301err_get_fwd:
302 esw_put_prio_table(esw, attr->chain, attr->prio, 0);
303err_get_fast:
e4ad91f2
CM
304 return rule;
305}
306
e52c2802
PB
307static void
308__mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
309 struct mlx5_flow_handle *rule,
310 struct mlx5_esw_flow_attr *attr,
311 bool fwd_rule)
312{
e85e02ba 313 bool split = (attr->split_count > 0);
e52c2802
PB
314
315 mlx5_del_flow_rules(rule);
316 esw->offloads.num_flows--;
317
318 if (fwd_rule) {
319 esw_put_prio_table(esw, attr->chain, attr->prio, 1);
320 esw_put_prio_table(esw, attr->chain, attr->prio, 0);
321 } else {
e85e02ba 322 esw_put_prio_table(esw, attr->chain, attr->prio, !!split);
e52c2802
PB
323 if (attr->dest_chain)
324 esw_put_prio_table(esw, attr->dest_chain, 1, 0);
325 }
326}
327
d85cdccb
OG
328void
329mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
330 struct mlx5_flow_handle *rule,
331 struct mlx5_esw_flow_attr *attr)
332{
e52c2802 333 __mlx5_eswitch_del_rule(esw, rule, attr, false);
d85cdccb
OG
334}
335
48265006
OG
336void
337mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
338 struct mlx5_flow_handle *rule,
339 struct mlx5_esw_flow_attr *attr)
340{
e52c2802 341 __mlx5_eswitch_del_rule(esw, rule, attr, true);
48265006
OG
342}
343
f5f82476
OG
344static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
345{
346 struct mlx5_eswitch_rep *rep;
411ec9e0 347 int i, err = 0;
f5f82476
OG
348
349 esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
411ec9e0 350 mlx5_esw_for_each_host_func_rep(esw, i, rep, esw->esw_funcs.num_vfs) {
8693115a 351 if (atomic_read(&rep->rep_data[REP_ETH].state) != REP_LOADED)
f5f82476
OG
352 continue;
353
354 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
355 if (err)
356 goto out;
357 }
358
359out:
360 return err;
361}
362
363static struct mlx5_eswitch_rep *
364esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
365{
366 struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
367
368 in_rep = attr->in_rep;
df65a573 369 out_rep = attr->dests[0].rep;
f5f82476
OG
370
371 if (push)
372 vport = in_rep;
373 else if (pop)
374 vport = out_rep;
375 else
376 vport = in_rep;
377
378 return vport;
379}
380
381static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
382 bool push, bool pop, bool fwd)
383{
384 struct mlx5_eswitch_rep *in_rep, *out_rep;
385
386 if ((push || pop) && !fwd)
387 goto out_notsupp;
388
389 in_rep = attr->in_rep;
df65a573 390 out_rep = attr->dests[0].rep;
f5f82476 391
b05af6aa 392 if (push && in_rep->vport == MLX5_VPORT_UPLINK)
f5f82476
OG
393 goto out_notsupp;
394
b05af6aa 395 if (pop && out_rep->vport == MLX5_VPORT_UPLINK)
f5f82476
OG
396 goto out_notsupp;
397
398 /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
399 if (!push && !pop && fwd)
b05af6aa 400 if (in_rep->vlan && out_rep->vport == MLX5_VPORT_UPLINK)
f5f82476
OG
401 goto out_notsupp;
402
403 /* protects against (1) setting rules with different vlans to push and
404 * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
405 */
1482bd3d 406 if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid[0]))
f5f82476
OG
407 goto out_notsupp;
408
409 return 0;
410
411out_notsupp:
9eb78923 412 return -EOPNOTSUPP;
f5f82476
OG
413}
414
415int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
416 struct mlx5_esw_flow_attr *attr)
417{
418 struct offloads_fdb *offloads = &esw->fdb_table.offloads;
419 struct mlx5_eswitch_rep *vport = NULL;
420 bool push, pop, fwd;
421 int err = 0;
422
6acfbf38 423 /* nop if we're on the vlan push/pop non emulation mode */
cc495188 424 if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
6acfbf38
OG
425 return 0;
426
f5f82476
OG
427 push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
428 pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
e52c2802
PB
429 fwd = !!((attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
430 !attr->dest_chain);
f5f82476
OG
431
432 err = esw_add_vlan_action_check(attr, push, pop, fwd);
433 if (err)
434 return err;
435
436 attr->vlan_handled = false;
437
438 vport = esw_vlan_action_get_vport(attr, push, pop);
439
440 if (!push && !pop && fwd) {
441 /* tracks VF --> wire rules without vlan push action */
b05af6aa 442 if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK) {
f5f82476
OG
443 vport->vlan_refcount++;
444 attr->vlan_handled = true;
445 }
446
447 return 0;
448 }
449
450 if (!push && !pop)
451 return 0;
452
453 if (!(offloads->vlan_push_pop_refcount)) {
454 /* it's the 1st vlan rule, apply global vlan pop policy */
455 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
456 if (err)
457 goto out;
458 }
459 offloads->vlan_push_pop_refcount++;
460
461 if (push) {
462 if (vport->vlan_refcount)
463 goto skip_set_push;
464
1482bd3d 465 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan_vid[0], 0,
f5f82476
OG
466 SET_VLAN_INSERT | SET_VLAN_STRIP);
467 if (err)
468 goto out;
1482bd3d 469 vport->vlan = attr->vlan_vid[0];
f5f82476
OG
470skip_set_push:
471 vport->vlan_refcount++;
472 }
473out:
474 if (!err)
475 attr->vlan_handled = true;
476 return err;
477}
478
479int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
480 struct mlx5_esw_flow_attr *attr)
481{
482 struct offloads_fdb *offloads = &esw->fdb_table.offloads;
483 struct mlx5_eswitch_rep *vport = NULL;
484 bool push, pop, fwd;
485 int err = 0;
486
6acfbf38 487 /* nop if we're on the vlan push/pop non emulation mode */
cc495188 488 if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
6acfbf38
OG
489 return 0;
490
f5f82476
OG
491 if (!attr->vlan_handled)
492 return 0;
493
494 push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
495 pop = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
496 fwd = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
497
498 vport = esw_vlan_action_get_vport(attr, push, pop);
499
500 if (!push && !pop && fwd) {
501 /* tracks VF --> wire rules without vlan push action */
b05af6aa 502 if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK)
f5f82476
OG
503 vport->vlan_refcount--;
504
505 return 0;
506 }
507
508 if (push) {
509 vport->vlan_refcount--;
510 if (vport->vlan_refcount)
511 goto skip_unset_push;
512
513 vport->vlan = 0;
514 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
515 0, 0, SET_VLAN_STRIP);
516 if (err)
517 goto out;
518 }
519
520skip_unset_push:
521 offloads->vlan_push_pop_refcount--;
522 if (offloads->vlan_push_pop_refcount)
523 return 0;
524
525 /* no more vlan rules, stop global vlan pop policy */
526 err = esw_set_global_vlan_pop(esw, 0);
527
528out:
529 return err;
530}
531
f7a68945 532struct mlx5_flow_handle *
ab22be9b
OG
533mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn)
534{
66958ed9 535 struct mlx5_flow_act flow_act = {0};
4c5009c5 536 struct mlx5_flow_destination dest = {};
74491de9 537 struct mlx5_flow_handle *flow_rule;
c5bb1730 538 struct mlx5_flow_spec *spec;
ab22be9b
OG
539 void *misc;
540
1b9a07ee 541 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
c5bb1730 542 if (!spec) {
ab22be9b
OG
543 flow_rule = ERR_PTR(-ENOMEM);
544 goto out;
545 }
546
c5bb1730 547 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
ab22be9b 548 MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
a1b3839a
BW
549 /* source vport is the esw manager */
550 MLX5_SET(fte_match_set_misc, misc, source_port, esw->manager_vport);
ab22be9b 551
c5bb1730 552 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
ab22be9b
OG
553 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
554 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
555
c5bb1730 556 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
ab22be9b 557 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
b17f7fc1 558 dest.vport.num = vport;
66958ed9 559 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
ab22be9b 560
52fff327 561 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
66958ed9 562 &flow_act, &dest, 1);
ab22be9b
OG
563 if (IS_ERR(flow_rule))
564 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
565out:
c5bb1730 566 kvfree(spec);
ab22be9b
OG
567 return flow_rule;
568}
57cbd893 569EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
ab22be9b 570
159fe639
MB
571void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
572{
573 mlx5_del_flow_rules(rule);
574}
575
c1286050
JL
576static int mlx5_eswitch_enable_passing_vport_metadata(struct mlx5_eswitch *esw)
577{
578 u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
579 u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
580 u8 fdb_to_vport_reg_c_id;
581 int err;
582
583 err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
584 out, sizeof(out));
585 if (err)
586 return err;
587
588 fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
589 esw_vport_context.fdb_to_vport_reg_c_id);
590
591 fdb_to_vport_reg_c_id |= MLX5_FDB_TO_VPORT_REG_C_0;
592 MLX5_SET(modify_esw_vport_context_in, in,
593 esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
594
595 MLX5_SET(modify_esw_vport_context_in, in,
596 field_select.fdb_to_vport_reg_c_id, 1);
597
598 return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
599 in, sizeof(in));
600}
601
602static int mlx5_eswitch_disable_passing_vport_metadata(struct mlx5_eswitch *esw)
603{
604 u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
605 u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {};
606 u8 fdb_to_vport_reg_c_id;
607 int err;
608
609 err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport,
610 out, sizeof(out));
611 if (err)
612 return err;
613
614 fdb_to_vport_reg_c_id = MLX5_GET(query_esw_vport_context_out, out,
615 esw_vport_context.fdb_to_vport_reg_c_id);
616
617 fdb_to_vport_reg_c_id &= ~MLX5_FDB_TO_VPORT_REG_C_0;
618
619 MLX5_SET(modify_esw_vport_context_in, in,
620 esw_vport_context.fdb_to_vport_reg_c_id, fdb_to_vport_reg_c_id);
621
622 MLX5_SET(modify_esw_vport_context_in, in,
623 field_select.fdb_to_vport_reg_c_id, 1);
624
625 return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport,
626 in, sizeof(in));
627}
628
a5641cb5
JL
629static void peer_miss_rules_setup(struct mlx5_eswitch *esw,
630 struct mlx5_core_dev *peer_dev,
ac004b83
RD
631 struct mlx5_flow_spec *spec,
632 struct mlx5_flow_destination *dest)
633{
a5641cb5 634 void *misc;
ac004b83 635
a5641cb5
JL
636 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
637 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
638 misc_parameters_2);
639 MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
ac004b83 640
a5641cb5
JL
641 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
642 } else {
643 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
644 misc_parameters);
ac004b83 645
a5641cb5
JL
646 MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
647 MLX5_CAP_GEN(peer_dev, vhca_id));
648
649 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
650
651 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
652 misc_parameters);
653 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
654 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
655 source_eswitch_owner_vhca_id);
656 }
ac004b83
RD
657
658 dest->type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
a1b3839a 659 dest->vport.num = peer_dev->priv.eswitch->manager_vport;
ac004b83 660 dest->vport.vhca_id = MLX5_CAP_GEN(peer_dev, vhca_id);
04de7dda 661 dest->vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
ac004b83
RD
662}
663
a5641cb5
JL
664static void esw_set_peer_miss_rule_source_port(struct mlx5_eswitch *esw,
665 struct mlx5_eswitch *peer_esw,
666 struct mlx5_flow_spec *spec,
667 u16 vport)
668{
669 void *misc;
670
671 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
672 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
673 misc_parameters_2);
674 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
675 mlx5_eswitch_get_vport_metadata_for_match(peer_esw,
676 vport));
677 } else {
678 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
679 misc_parameters);
680 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
681 }
682}
683
ac004b83
RD
684static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
685 struct mlx5_core_dev *peer_dev)
686{
687 struct mlx5_flow_destination dest = {};
688 struct mlx5_flow_act flow_act = {0};
689 struct mlx5_flow_handle **flows;
690 struct mlx5_flow_handle *flow;
691 struct mlx5_flow_spec *spec;
692 /* total vports is the same for both e-switches */
693 int nvports = esw->total_vports;
694 void *misc;
695 int err, i;
696
697 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
698 if (!spec)
699 return -ENOMEM;
700
a5641cb5 701 peer_miss_rules_setup(esw, peer_dev, spec, &dest);
ac004b83
RD
702
703 flows = kvzalloc(nvports * sizeof(*flows), GFP_KERNEL);
704 if (!flows) {
705 err = -ENOMEM;
706 goto alloc_flows_err;
707 }
708
709 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
710 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
711 misc_parameters);
712
81cd229c 713 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
a5641cb5
JL
714 esw_set_peer_miss_rule_source_port(esw, peer_dev->priv.eswitch,
715 spec, MLX5_VPORT_PF);
716
81cd229c
BW
717 flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
718 spec, &flow_act, &dest, 1);
719 if (IS_ERR(flow)) {
720 err = PTR_ERR(flow);
721 goto add_pf_flow_err;
722 }
723 flows[MLX5_VPORT_PF] = flow;
724 }
725
726 if (mlx5_ecpf_vport_exists(esw->dev)) {
727 MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_ECPF);
728 flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
729 spec, &flow_act, &dest, 1);
730 if (IS_ERR(flow)) {
731 err = PTR_ERR(flow);
732 goto add_ecpf_flow_err;
733 }
734 flows[mlx5_eswitch_ecpf_idx(esw)] = flow;
735 }
736
786ef904 737 mlx5_esw_for_each_vf_vport_num(esw, i, mlx5_core_max_vfs(esw->dev)) {
a5641cb5
JL
738 esw_set_peer_miss_rule_source_port(esw,
739 peer_dev->priv.eswitch,
740 spec, i);
741
ac004b83
RD
742 flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
743 spec, &flow_act, &dest, 1);
744 if (IS_ERR(flow)) {
745 err = PTR_ERR(flow);
81cd229c 746 goto add_vf_flow_err;
ac004b83
RD
747 }
748 flows[i] = flow;
749 }
750
751 esw->fdb_table.offloads.peer_miss_rules = flows;
752
753 kvfree(spec);
754 return 0;
755
81cd229c 756add_vf_flow_err:
879c8f84 757 nvports = --i;
786ef904 758 mlx5_esw_for_each_vf_vport_num_reverse(esw, i, nvports)
ac004b83 759 mlx5_del_flow_rules(flows[i]);
81cd229c
BW
760
761 if (mlx5_ecpf_vport_exists(esw->dev))
762 mlx5_del_flow_rules(flows[mlx5_eswitch_ecpf_idx(esw)]);
763add_ecpf_flow_err:
764 if (mlx5_core_is_ecpf_esw_manager(esw->dev))
765 mlx5_del_flow_rules(flows[MLX5_VPORT_PF]);
766add_pf_flow_err:
767 esw_warn(esw->dev, "FDB: Failed to add peer miss flow rule err %d\n", err);
ac004b83
RD
768 kvfree(flows);
769alloc_flows_err:
770 kvfree(spec);
771 return err;
772}
773
774static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw)
775{
776 struct mlx5_flow_handle **flows;
777 int i;
778
779 flows = esw->fdb_table.offloads.peer_miss_rules;
780
786ef904
PP
781 mlx5_esw_for_each_vf_vport_num_reverse(esw, i,
782 mlx5_core_max_vfs(esw->dev))
ac004b83
RD
783 mlx5_del_flow_rules(flows[i]);
784
81cd229c
BW
785 if (mlx5_ecpf_vport_exists(esw->dev))
786 mlx5_del_flow_rules(flows[mlx5_eswitch_ecpf_idx(esw)]);
787
788 if (mlx5_core_is_ecpf_esw_manager(esw->dev))
789 mlx5_del_flow_rules(flows[MLX5_VPORT_PF]);
790
ac004b83
RD
791 kvfree(flows);
792}
793
3aa33572
OG
794static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
795{
66958ed9 796 struct mlx5_flow_act flow_act = {0};
4c5009c5 797 struct mlx5_flow_destination dest = {};
74491de9 798 struct mlx5_flow_handle *flow_rule = NULL;
c5bb1730 799 struct mlx5_flow_spec *spec;
f80be543
MB
800 void *headers_c;
801 void *headers_v;
3aa33572 802 int err = 0;
f80be543
MB
803 u8 *dmac_c;
804 u8 *dmac_v;
3aa33572 805
1b9a07ee 806 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
c5bb1730 807 if (!spec) {
3aa33572
OG
808 err = -ENOMEM;
809 goto out;
810 }
811
f80be543
MB
812 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
813 headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
814 outer_headers);
815 dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
816 outer_headers.dmac_47_16);
817 dmac_c[0] = 0x01;
818
3aa33572 819 dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
a1b3839a 820 dest.vport.num = esw->manager_vport;
66958ed9 821 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
3aa33572 822
52fff327 823 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
66958ed9 824 &flow_act, &dest, 1);
3aa33572
OG
825 if (IS_ERR(flow_rule)) {
826 err = PTR_ERR(flow_rule);
f80be543 827 esw_warn(esw->dev, "FDB: Failed to add unicast miss flow rule err %d\n", err);
3aa33572
OG
828 goto out;
829 }
830
f80be543
MB
831 esw->fdb_table.offloads.miss_rule_uni = flow_rule;
832
833 headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
834 outer_headers);
835 dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
836 outer_headers.dmac_47_16);
837 dmac_v[0] = 0x01;
52fff327 838 flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
f80be543
MB
839 &flow_act, &dest, 1);
840 if (IS_ERR(flow_rule)) {
841 err = PTR_ERR(flow_rule);
842 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
843 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
844 goto out;
845 }
846
847 esw->fdb_table.offloads.miss_rule_multi = flow_rule;
848
3aa33572 849out:
c5bb1730 850 kvfree(spec);
3aa33572
OG
851 return err;
852}
853
1033665e 854#define ESW_OFFLOADS_NUM_GROUPS 4
69697b6e 855
e52c2802
PB
856/* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS),
857 * and a virtual memory region of 16M (ESW_SIZE), this region is duplicated
858 * for each flow table pool. We can allocate up to 16M of each pool,
859 * and we keep track of how much we used via put/get_sz_to_pool.
860 * Firmware doesn't report any of this for now.
861 * ESW_POOL is expected to be sorted from large to small
862 */
863#define ESW_SIZE (16 * 1024 * 1024)
864const unsigned int ESW_POOLS[4] = { 4 * 1024 * 1024, 1 * 1024 * 1024,
865 64 * 1024, 4 * 1024 };
866
867static int
868get_sz_from_pool(struct mlx5_eswitch *esw)
869{
870 int sz = 0, i;
871
872 for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
873 if (esw->fdb_table.offloads.fdb_left[i]) {
874 --esw->fdb_table.offloads.fdb_left[i];
875 sz = ESW_POOLS[i];
876 break;
877 }
878 }
879
880 return sz;
881}
882
883static void
884put_sz_to_pool(struct mlx5_eswitch *esw, int sz)
885{
886 int i;
887
888 for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
889 if (sz >= ESW_POOLS[i]) {
890 ++esw->fdb_table.offloads.fdb_left[i];
891 break;
892 }
893 }
894}
895
896static struct mlx5_flow_table *
897create_next_size_table(struct mlx5_eswitch *esw,
898 struct mlx5_flow_namespace *ns,
899 u16 table_prio,
900 int level,
901 u32 flags)
902{
903 struct mlx5_flow_table *fdb;
904 int sz;
905
906 sz = get_sz_from_pool(esw);
907 if (!sz)
908 return ERR_PTR(-ENOSPC);
909
910 fdb = mlx5_create_auto_grouped_flow_table(ns,
911 table_prio,
912 sz,
913 ESW_OFFLOADS_NUM_GROUPS,
914 level,
915 flags);
916 if (IS_ERR(fdb)) {
917 esw_warn(esw->dev, "Failed to create FDB Table err %d (table prio: %d, level: %d, size: %d)\n",
918 (int)PTR_ERR(fdb), table_prio, level, sz);
919 put_sz_to_pool(esw, sz);
920 }
921
922 return fdb;
923}
924
925static struct mlx5_flow_table *
926esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
69697b6e 927{
69697b6e 928 struct mlx5_core_dev *dev = esw->dev;
69697b6e 929 struct mlx5_flow_table *fdb = NULL;
e52c2802
PB
930 struct mlx5_flow_namespace *ns;
931 int table_prio, l = 0;
bbd00f7e 932 u32 flags = 0;
69697b6e 933
c92a0b94
PB
934 if (chain == FDB_SLOW_PATH_CHAIN)
935 return esw->fdb_table.offloads.slow_fdb;
936
e52c2802 937 mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
264d7bf3 938
e52c2802
PB
939 fdb = fdb_prio_table(esw, chain, prio, level).fdb;
940 if (fdb) {
941 /* take ref on earlier levels as well */
942 while (level >= 0)
943 fdb_prio_table(esw, chain, prio, level--).num_rules++;
944 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
945 return fdb;
946 }
69697b6e 947
e52c2802
PB
948 ns = mlx5_get_fdb_sub_ns(dev, chain);
949 if (!ns) {
950 esw_warn(dev, "Failed to get FDB sub namespace\n");
951 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
952 return ERR_PTR(-EOPNOTSUPP);
953 }
a842dd04 954
7768d197 955 if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
60786f09 956 flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
61444b45 957 MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
bbd00f7e 958
e52c2802 959 table_prio = (chain * FDB_MAX_PRIO) + prio - 1;
69697b6e 960
e52c2802
PB
961 /* create earlier levels for correct fs_core lookup when
962 * connecting tables
963 */
964 for (l = 0; l <= level; l++) {
965 if (fdb_prio_table(esw, chain, prio, l).fdb) {
966 fdb_prio_table(esw, chain, prio, l).num_rules++;
967 continue;
968 }
a842dd04 969
e52c2802
PB
970 fdb = create_next_size_table(esw, ns, table_prio, l, flags);
971 if (IS_ERR(fdb)) {
972 l--;
973 goto err_create_fdb;
974 }
975
976 fdb_prio_table(esw, chain, prio, l).fdb = fdb;
977 fdb_prio_table(esw, chain, prio, l).num_rules = 1;
a842dd04 978 }
a842dd04 979
e52c2802
PB
980 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
981 return fdb;
a842dd04 982
e52c2802
PB
983err_create_fdb:
984 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
985 if (l >= 0)
986 esw_put_prio_table(esw, chain, prio, l);
987
988 return fdb;
1967ce6e
OG
989}
990
e52c2802
PB
991static void
992esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
1967ce6e 993{
e52c2802
PB
994 int l;
995
c92a0b94
PB
996 if (chain == FDB_SLOW_PATH_CHAIN)
997 return;
998
e52c2802
PB
999 mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
1000
1001 for (l = level; l >= 0; l--) {
1002 if (--(fdb_prio_table(esw, chain, prio, l).num_rules) > 0)
1003 continue;
1004
1005 put_sz_to_pool(esw, fdb_prio_table(esw, chain, prio, l).fdb->max_fte);
1006 mlx5_destroy_flow_table(fdb_prio_table(esw, chain, prio, l).fdb);
1007 fdb_prio_table(esw, chain, prio, l).fdb = NULL;
1008 }
1009
1010 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
1011}
1012
1013static void esw_destroy_offloads_fast_fdb_tables(struct mlx5_eswitch *esw)
1014{
1015 /* If lazy creation isn't supported, deref the fast path tables */
1016 if (!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)) {
1017 esw_put_prio_table(esw, 0, 1, 1);
1018 esw_put_prio_table(esw, 0, 1, 0);
1019 }
1967ce6e
OG
1020}
1021
1022#define MAX_PF_SQ 256
cd3d07e7 1023#define MAX_SQ_NVPORTS 32
1967ce6e 1024
a5641cb5
JL
1025static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw,
1026 u32 *flow_group_in)
1027{
1028 void *match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1029 flow_group_in,
1030 match_criteria);
1031
1032 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1033 MLX5_SET(create_flow_group_in, flow_group_in,
1034 match_criteria_enable,
1035 MLX5_MATCH_MISC_PARAMETERS_2);
1036
1037 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1038 misc_parameters_2.metadata_reg_c_0);
1039 } else {
1040 MLX5_SET(create_flow_group_in, flow_group_in,
1041 match_criteria_enable,
1042 MLX5_MATCH_MISC_PARAMETERS);
1043
1044 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1045 misc_parameters.source_port);
1046 }
1047}
1048
1967ce6e
OG
1049static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
1050{
1051 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1052 struct mlx5_flow_table_attr ft_attr = {};
1053 struct mlx5_core_dev *dev = esw->dev;
e52c2802 1054 u32 *flow_group_in, max_flow_counter;
1967ce6e
OG
1055 struct mlx5_flow_namespace *root_ns;
1056 struct mlx5_flow_table *fdb = NULL;
e52c2802 1057 int table_size, ix, err = 0, i;
1967ce6e 1058 struct mlx5_flow_group *g;
e52c2802 1059 u32 flags = 0, fdb_max;
1967ce6e 1060 void *match_criteria;
f80be543 1061 u8 *dmac;
1967ce6e
OG
1062
1063 esw_debug(esw->dev, "Create offloads FDB Tables\n");
1b9a07ee 1064 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1967ce6e
OG
1065 if (!flow_group_in)
1066 return -ENOMEM;
1067
1068 root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
1069 if (!root_ns) {
1070 esw_warn(dev, "Failed to get FDB flow namespace\n");
1071 err = -EOPNOTSUPP;
1072 goto ns_err;
1073 }
1074
e52c2802
PB
1075 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
1076 MLX5_CAP_GEN(dev, max_flow_counter_15_0);
1077 fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size);
1078
1079 esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d), groups(%d), max flow table size(2^%d))\n",
1080 MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
1081 max_flow_counter, ESW_OFFLOADS_NUM_GROUPS,
1082 fdb_max);
1083
1084 for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++)
1085 esw->fdb_table.offloads.fdb_left[i] =
1086 ESW_POOLS[i] <= fdb_max ? ESW_SIZE / ESW_POOLS[i] : 0;
1967ce6e 1087
cd7e4186
BW
1088 table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ +
1089 MLX5_ESW_MISS_FLOWS + esw->total_vports;
b3ba5149 1090
e52c2802
PB
1091 /* create the slow path fdb with encap set, so further table instances
1092 * can be created at run time while VFs are probed if the FW allows that.
1093 */
1094 if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
1095 flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
1096 MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
1097
1098 ft_attr.flags = flags;
b3ba5149
ES
1099 ft_attr.max_fte = table_size;
1100 ft_attr.prio = FDB_SLOW_PATH;
1101
1102 fdb = mlx5_create_flow_table(root_ns, &ft_attr);
1033665e
OG
1103 if (IS_ERR(fdb)) {
1104 err = PTR_ERR(fdb);
1105 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
1106 goto slow_fdb_err;
1107 }
52fff327 1108 esw->fdb_table.offloads.slow_fdb = fdb;
1033665e 1109
e52c2802
PB
1110 /* If lazy creation isn't supported, open the fast path tables now */
1111 if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, multi_fdb_encap) &&
1112 esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
1113 esw->fdb_table.flags &= ~ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
1114 esw_warn(dev, "Lazy creation of flow tables isn't supported, ignoring priorities\n");
1115 esw_get_prio_table(esw, 0, 1, 0);
1116 esw_get_prio_table(esw, 0, 1, 1);
1117 } else {
1118 esw_debug(dev, "Lazy creation of flow tables supported, deferring table opening\n");
1119 esw->fdb_table.flags |= ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
1120 }
1121
69697b6e
OG
1122 /* create send-to-vport group */
1123 memset(flow_group_in, 0, inlen);
1124 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1125 MLX5_MATCH_MISC_PARAMETERS);
1126
1127 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1128
1129 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
1130 MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
1131
cd3d07e7 1132 ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
69697b6e
OG
1133 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1134 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
1135
1136 g = mlx5_create_flow_group(fdb, flow_group_in);
1137 if (IS_ERR(g)) {
1138 err = PTR_ERR(g);
1139 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
1140 goto send_vport_err;
1141 }
1142 esw->fdb_table.offloads.send_to_vport_grp = g;
1143
ac004b83
RD
1144 /* create peer esw miss group */
1145 memset(flow_group_in, 0, inlen);
ac004b83 1146
a5641cb5
JL
1147 esw_set_flow_group_source_port(esw, flow_group_in);
1148
1149 if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1150 match_criteria = MLX5_ADDR_OF(create_flow_group_in,
1151 flow_group_in,
1152 match_criteria);
ac004b83 1153
a5641cb5
JL
1154 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
1155 misc_parameters.source_eswitch_owner_vhca_id);
1156
1157 MLX5_SET(create_flow_group_in, flow_group_in,
1158 source_eswitch_owner_vhca_id_valid, 1);
1159 }
ac004b83 1160
ac004b83
RD
1161 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
1162 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1163 ix + esw->total_vports - 1);
1164 ix += esw->total_vports;
1165
1166 g = mlx5_create_flow_group(fdb, flow_group_in);
1167 if (IS_ERR(g)) {
1168 err = PTR_ERR(g);
1169 esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
1170 goto peer_miss_err;
1171 }
1172 esw->fdb_table.offloads.peer_miss_grp = g;
1173
69697b6e
OG
1174 /* create miss group */
1175 memset(flow_group_in, 0, inlen);
f80be543
MB
1176 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1177 MLX5_MATCH_OUTER_HEADERS);
1178 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
1179 match_criteria);
1180 dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
1181 outer_headers.dmac_47_16);
1182 dmac[0] = 0x01;
69697b6e
OG
1183
1184 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
cd7e4186
BW
1185 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1186 ix + MLX5_ESW_MISS_FLOWS);
69697b6e
OG
1187
1188 g = mlx5_create_flow_group(fdb, flow_group_in);
1189 if (IS_ERR(g)) {
1190 err = PTR_ERR(g);
1191 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
1192 goto miss_err;
1193 }
1194 esw->fdb_table.offloads.miss_grp = g;
1195
3aa33572
OG
1196 err = esw_add_fdb_miss_rule(esw);
1197 if (err)
1198 goto miss_rule_err;
1199
e52c2802 1200 esw->nvports = nvports;
c88a026e 1201 kvfree(flow_group_in);
69697b6e
OG
1202 return 0;
1203
3aa33572
OG
1204miss_rule_err:
1205 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
69697b6e 1206miss_err:
ac004b83
RD
1207 mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1208peer_miss_err:
69697b6e
OG
1209 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1210send_vport_err:
e52c2802 1211 esw_destroy_offloads_fast_fdb_tables(esw);
52fff327 1212 mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
1033665e 1213slow_fdb_err:
69697b6e
OG
1214ns_err:
1215 kvfree(flow_group_in);
1216 return err;
1217}
1218
1967ce6e 1219static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
69697b6e 1220{
e52c2802 1221 if (!esw->fdb_table.offloads.slow_fdb)
69697b6e
OG
1222 return;
1223
1967ce6e 1224 esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
f80be543
MB
1225 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
1226 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
69697b6e 1227 mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
ac004b83 1228 mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
69697b6e
OG
1229 mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1230
52fff327 1231 mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
e52c2802 1232 esw_destroy_offloads_fast_fdb_tables(esw);
69697b6e 1233}
c116c6ee 1234
cd7e4186 1235static int esw_create_offloads_table(struct mlx5_eswitch *esw, int nvports)
c116c6ee 1236{
b3ba5149 1237 struct mlx5_flow_table_attr ft_attr = {};
c116c6ee 1238 struct mlx5_core_dev *dev = esw->dev;
b3ba5149
ES
1239 struct mlx5_flow_table *ft_offloads;
1240 struct mlx5_flow_namespace *ns;
c116c6ee
OG
1241 int err = 0;
1242
1243 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
1244 if (!ns) {
1245 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
eff596da 1246 return -EOPNOTSUPP;
c116c6ee
OG
1247 }
1248
cd7e4186 1249 ft_attr.max_fte = nvports + MLX5_ESW_MISS_FLOWS;
b3ba5149
ES
1250
1251 ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
c116c6ee
OG
1252 if (IS_ERR(ft_offloads)) {
1253 err = PTR_ERR(ft_offloads);
1254 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
1255 return err;
1256 }
1257
1258 esw->offloads.ft_offloads = ft_offloads;
1259 return 0;
1260}
1261
1262static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
1263{
1264 struct mlx5_esw_offload *offloads = &esw->offloads;
1265
1266 mlx5_destroy_flow_table(offloads->ft_offloads);
1267}
fed9ce22 1268
cd7e4186 1269static int esw_create_vport_rx_group(struct mlx5_eswitch *esw, int nvports)
fed9ce22
OG
1270{
1271 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1272 struct mlx5_flow_group *g;
fed9ce22 1273 u32 *flow_group_in;
fed9ce22 1274 int err = 0;
fed9ce22 1275
cd7e4186 1276 nvports = nvports + MLX5_ESW_MISS_FLOWS;
1b9a07ee 1277 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
fed9ce22
OG
1278 if (!flow_group_in)
1279 return -ENOMEM;
1280
1281 /* create vport rx group */
1282 memset(flow_group_in, 0, inlen);
fed9ce22 1283
a5641cb5 1284 esw_set_flow_group_source_port(esw, flow_group_in);
fed9ce22
OG
1285
1286 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1287 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
1288
1289 g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
1290
1291 if (IS_ERR(g)) {
1292 err = PTR_ERR(g);
1293 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
1294 goto out;
1295 }
1296
1297 esw->offloads.vport_rx_group = g;
1298out:
e574978a 1299 kvfree(flow_group_in);
fed9ce22
OG
1300 return err;
1301}
1302
1303static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
1304{
1305 mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
1306}
1307
74491de9 1308struct mlx5_flow_handle *
c966f7d5
GT
1309mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport,
1310 struct mlx5_flow_destination *dest)
fed9ce22 1311{
66958ed9 1312 struct mlx5_flow_act flow_act = {0};
74491de9 1313 struct mlx5_flow_handle *flow_rule;
c5bb1730 1314 struct mlx5_flow_spec *spec;
fed9ce22
OG
1315 void *misc;
1316
1b9a07ee 1317 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
c5bb1730 1318 if (!spec) {
fed9ce22
OG
1319 flow_rule = ERR_PTR(-ENOMEM);
1320 goto out;
1321 }
1322
a5641cb5
JL
1323 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1324 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
1325 MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0,
1326 mlx5_eswitch_get_vport_metadata_for_match(esw, vport));
fed9ce22 1327
a5641cb5
JL
1328 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
1329 MLX5_SET_TO_ONES(fte_match_set_misc2, misc, metadata_reg_c_0);
fed9ce22 1330
a5641cb5
JL
1331 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
1332 } else {
1333 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
1334 MLX5_SET(fte_match_set_misc, misc, source_port, vport);
1335
1336 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
1337 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1338
1339 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
1340 }
fed9ce22 1341
66958ed9 1342 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
74491de9 1343 flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
c966f7d5 1344 &flow_act, dest, 1);
fed9ce22
OG
1345 if (IS_ERR(flow_rule)) {
1346 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
1347 goto out;
1348 }
1349
1350out:
c5bb1730 1351 kvfree(spec);
fed9ce22
OG
1352 return flow_rule;
1353}
feae9087 1354
db7ff19e
EB
1355static int esw_offloads_start(struct mlx5_eswitch *esw,
1356 struct netlink_ext_ack *extack)
c930a3ad 1357{
062f4bf4 1358 int err, err1;
c930a3ad 1359
f6455de0 1360 if (esw->mode != MLX5_ESWITCH_LEGACY &&
c96692fb 1361 !mlx5_core_is_ecpf_esw_manager(esw->dev)) {
8c98ee77
EB
1362 NL_SET_ERR_MSG_MOD(extack,
1363 "Can't set offloads mode, SRIOV legacy not enabled");
c930a3ad
OG
1364 return -EINVAL;
1365 }
1366
f6455de0 1367 mlx5_eswitch_disable(esw);
062f4bf4
BW
1368 mlx5_eswitch_update_num_of_vfs(esw, esw->dev->priv.sriov.num_vfs);
1369 err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
6c419ba8 1370 if (err) {
8c98ee77
EB
1371 NL_SET_ERR_MSG_MOD(extack,
1372 "Failed setting eswitch to offloads");
062f4bf4 1373 err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
8c98ee77
EB
1374 if (err1) {
1375 NL_SET_ERR_MSG_MOD(extack,
1376 "Failed setting eswitch back to legacy");
1377 }
6c419ba8 1378 }
bffaa916
RD
1379 if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
1380 if (mlx5_eswitch_inline_mode_get(esw,
bffaa916
RD
1381 &esw->offloads.inline_mode)) {
1382 esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
8c98ee77
EB
1383 NL_SET_ERR_MSG_MOD(extack,
1384 "Inline mode is different between vports");
bffaa916
RD
1385 }
1386 }
c930a3ad
OG
1387 return err;
1388}
1389
e8d31c4d
MB
1390void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
1391{
1392 kfree(esw->offloads.vport_reps);
1393}
1394
1395int esw_offloads_init_reps(struct mlx5_eswitch *esw)
1396{
2752b823 1397 int total_vports = esw->total_vports;
e8d31c4d 1398 struct mlx5_core_dev *dev = esw->dev;
e8d31c4d 1399 struct mlx5_eswitch_rep *rep;
f121e0ea 1400 u8 hw_id[ETH_ALEN], rep_type;
d6518db2 1401 int vport_index;
e8d31c4d 1402
2aca1787 1403 esw->offloads.vport_reps = kcalloc(total_vports,
e8d31c4d
MB
1404 sizeof(struct mlx5_eswitch_rep),
1405 GFP_KERNEL);
1406 if (!esw->offloads.vport_reps)
1407 return -ENOMEM;
1408
e1d974d0 1409 mlx5_query_mac_address(dev, hw_id);
e8d31c4d 1410
d6518db2
BW
1411 mlx5_esw_for_all_reps(esw, vport_index, rep) {
1412 rep->vport = mlx5_eswitch_index_to_vport_num(esw, vport_index);
2f69e591 1413 rep->vport_index = vport_index;
e8d31c4d 1414 ether_addr_copy(rep->hw_id, hw_id);
f121e0ea
BW
1415
1416 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++)
8693115a 1417 atomic_set(&rep->rep_data[rep_type].state,
6f4e0219 1418 REP_UNREGISTERED);
e8d31c4d
MB
1419 }
1420
e8d31c4d
MB
1421 return 0;
1422}
1423
c9b99abc
BW
1424static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw,
1425 struct mlx5_eswitch_rep *rep, u8 rep_type)
1426{
8693115a 1427 if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
6f4e0219 1428 REP_LOADED, REP_REGISTERED) == REP_LOADED)
8693115a 1429 esw->offloads.rep_ops[rep_type]->unload(rep);
c9b99abc
BW
1430}
1431
29d9fd7d 1432static void __unload_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
6ed1803a
MB
1433{
1434 struct mlx5_eswitch_rep *rep;
c9b99abc 1435
81cd229c
BW
1436 if (mlx5_ecpf_vport_exists(esw->dev)) {
1437 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_ECPF);
1438 __esw_offloads_unload_rep(esw, rep, rep_type);
1439 }
1440
1441 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1442 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
1443 __esw_offloads_unload_rep(esw, rep, rep_type);
1444 }
1445
879c8f84 1446 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
c9b99abc 1447 __esw_offloads_unload_rep(esw, rep, rep_type);
6ed1803a
MB
1448}
1449
29d9fd7d
BW
1450static void __unload_reps_vf_vport(struct mlx5_eswitch *esw, int nvports,
1451 u8 rep_type)
1452{
1453 struct mlx5_eswitch_rep *rep;
1454 int i;
1455
1456 mlx5_esw_for_each_vf_rep_reverse(esw, i, rep, nvports)
1457 __esw_offloads_unload_rep(esw, rep, rep_type);
1458}
1459
1460static void esw_offloads_unload_vf_reps(struct mlx5_eswitch *esw, int nvports)
1461{
1462 u8 rep_type = NUM_REP_TYPES;
1463
1464 while (rep_type-- > 0)
1465 __unload_reps_vf_vport(esw, nvports, rep_type);
1466}
1467
062f4bf4 1468static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
29d9fd7d 1469{
062f4bf4 1470 __unload_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
29d9fd7d
BW
1471
1472 /* Special vports must be the last to unload. */
1473 __unload_reps_special_vport(esw, rep_type);
1474}
1475
062f4bf4 1476static void esw_offloads_unload_all_reps(struct mlx5_eswitch *esw)
a4b97ab4
MB
1477{
1478 u8 rep_type = NUM_REP_TYPES;
1479
1480 while (rep_type-- > 0)
062f4bf4 1481 __unload_reps_all_vport(esw, rep_type);
a4b97ab4
MB
1482}
1483
c9b99abc
BW
1484static int __esw_offloads_load_rep(struct mlx5_eswitch *esw,
1485 struct mlx5_eswitch_rep *rep, u8 rep_type)
1486{
f121e0ea
BW
1487 int err = 0;
1488
8693115a 1489 if (atomic_cmpxchg(&rep->rep_data[rep_type].state,
6f4e0219 1490 REP_REGISTERED, REP_LOADED) == REP_REGISTERED) {
8693115a 1491 err = esw->offloads.rep_ops[rep_type]->load(esw->dev, rep);
6f4e0219 1492 if (err)
8693115a 1493 atomic_set(&rep->rep_data[rep_type].state,
6f4e0219
BW
1494 REP_REGISTERED);
1495 }
f121e0ea 1496
6f4e0219 1497 return err;
c9b99abc
BW
1498}
1499
29d9fd7d 1500static int __load_reps_special_vport(struct mlx5_eswitch *esw, u8 rep_type)
c930a3ad 1501{
cb67b832 1502 struct mlx5_eswitch_rep *rep;
c930a3ad
OG
1503 int err;
1504
879c8f84 1505 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
c9b99abc 1506 err = __esw_offloads_load_rep(esw, rep, rep_type);
81cd229c
BW
1507 if (err)
1508 return err;
1509
1510 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1511 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
1512 err = __esw_offloads_load_rep(esw, rep, rep_type);
1513 if (err)
1514 goto err_pf;
1515 }
1516
1517 if (mlx5_ecpf_vport_exists(esw->dev)) {
1518 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_ECPF);
1519 err = __esw_offloads_load_rep(esw, rep, rep_type);
1520 if (err)
1521 goto err_ecpf;
1522 }
1523
1524 return 0;
1525
1526err_ecpf:
1527 if (mlx5_core_is_ecpf_esw_manager(esw->dev)) {
1528 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF);
1529 __esw_offloads_unload_rep(esw, rep, rep_type);
1530 }
1531
1532err_pf:
1533 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
1534 __esw_offloads_unload_rep(esw, rep, rep_type);
29d9fd7d
BW
1535 return err;
1536}
6ed1803a 1537
29d9fd7d
BW
1538static int __load_reps_vf_vport(struct mlx5_eswitch *esw, int nvports,
1539 u8 rep_type)
1540{
1541 struct mlx5_eswitch_rep *rep;
1542 int err, i;
1543
1544 mlx5_esw_for_each_vf_rep(esw, i, rep, nvports) {
c9b99abc 1545 err = __esw_offloads_load_rep(esw, rep, rep_type);
6ed1803a 1546 if (err)
29d9fd7d 1547 goto err_vf;
6ed1803a
MB
1548 }
1549
1550 return 0;
1551
29d9fd7d
BW
1552err_vf:
1553 __unload_reps_vf_vport(esw, --i, rep_type);
1554 return err;
1555}
1556
062f4bf4
BW
1557static int __load_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type)
1558{
1559 int err;
1560
1561 /* Special vports must be loaded first, uplink rep creates mdev resource. */
1562 err = __load_reps_special_vport(esw, rep_type);
1563 if (err)
1564 return err;
1565
1566 err = __load_reps_vf_vport(esw, esw->esw_funcs.num_vfs, rep_type);
1567 if (err)
1568 goto err_vfs;
1569
1570 return 0;
1571
1572err_vfs:
1573 __unload_reps_special_vport(esw, rep_type);
1574 return err;
1575}
1576
29d9fd7d
BW
1577static int esw_offloads_load_vf_reps(struct mlx5_eswitch *esw, int nvports)
1578{
1579 u8 rep_type = 0;
1580 int err;
1581
1582 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
1583 err = __load_reps_vf_vport(esw, nvports, rep_type);
1584 if (err)
1585 goto err_reps;
1586 }
1587
1588 return err;
1589
6ed1803a 1590err_reps:
29d9fd7d
BW
1591 while (rep_type-- > 0)
1592 __unload_reps_vf_vport(esw, nvports, rep_type);
1593 return err;
1594}
1595
062f4bf4 1596static int esw_offloads_load_all_reps(struct mlx5_eswitch *esw)
a4b97ab4
MB
1597{
1598 u8 rep_type = 0;
1599 int err;
1600
1601 for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
062f4bf4 1602 err = __load_reps_all_vport(esw, rep_type);
a4b97ab4
MB
1603 if (err)
1604 goto err_reps;
1605 }
1606
1607 return err;
1608
1609err_reps:
1610 while (rep_type-- > 0)
062f4bf4 1611 __unload_reps_all_vport(esw, rep_type);
6ed1803a
MB
1612 return err;
1613}
1614
ac004b83
RD
1615#define ESW_OFFLOADS_DEVCOM_PAIR (0)
1616#define ESW_OFFLOADS_DEVCOM_UNPAIR (1)
1617
1618static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw,
1619 struct mlx5_eswitch *peer_esw)
1620{
1621 int err;
1622
1623 err = esw_add_fdb_peer_miss_rules(esw, peer_esw->dev);
1624 if (err)
1625 return err;
1626
1627 return 0;
1628}
1629
1630static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw)
1631{
04de7dda 1632 mlx5e_tc_clean_fdb_peer_flows(esw);
ac004b83
RD
1633 esw_del_fdb_peer_miss_rules(esw);
1634}
1635
1636static int mlx5_esw_offloads_devcom_event(int event,
1637 void *my_data,
1638 void *event_data)
1639{
1640 struct mlx5_eswitch *esw = my_data;
1641 struct mlx5_eswitch *peer_esw = event_data;
1642 struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1643 int err;
1644
1645 switch (event) {
1646 case ESW_OFFLOADS_DEVCOM_PAIR:
a5641cb5
JL
1647 if (mlx5_eswitch_vport_match_metadata_enabled(esw) !=
1648 mlx5_eswitch_vport_match_metadata_enabled(peer_esw))
1649 break;
1650
ac004b83
RD
1651 err = mlx5_esw_offloads_pair(esw, peer_esw);
1652 if (err)
1653 goto err_out;
1654
1655 err = mlx5_esw_offloads_pair(peer_esw, esw);
1656 if (err)
1657 goto err_pair;
1658
1659 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true);
1660 break;
1661
1662 case ESW_OFFLOADS_DEVCOM_UNPAIR:
1663 if (!mlx5_devcom_is_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
1664 break;
1665
1666 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false);
1667 mlx5_esw_offloads_unpair(peer_esw);
1668 mlx5_esw_offloads_unpair(esw);
1669 break;
1670 }
1671
1672 return 0;
1673
1674err_pair:
1675 mlx5_esw_offloads_unpair(esw);
1676
1677err_out:
1678 mlx5_core_err(esw->dev, "esw offloads devcom event failure, event %u err %d",
1679 event, err);
1680 return err;
1681}
1682
1683static void esw_offloads_devcom_init(struct mlx5_eswitch *esw)
1684{
1685 struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1686
04de7dda
RD
1687 INIT_LIST_HEAD(&esw->offloads.peer_flows);
1688 mutex_init(&esw->offloads.peer_mutex);
1689
ac004b83
RD
1690 if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
1691 return;
1692
1693 mlx5_devcom_register_component(devcom,
1694 MLX5_DEVCOM_ESW_OFFLOADS,
1695 mlx5_esw_offloads_devcom_event,
1696 esw);
1697
1698 mlx5_devcom_send_event(devcom,
1699 MLX5_DEVCOM_ESW_OFFLOADS,
1700 ESW_OFFLOADS_DEVCOM_PAIR, esw);
1701}
1702
1703static void esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
1704{
1705 struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1706
1707 if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
1708 return;
1709
1710 mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
1711 ESW_OFFLOADS_DEVCOM_UNPAIR, esw);
1712
1713 mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
1714}
1715
18486737
EB
1716static int esw_vport_ingress_prio_tag_config(struct mlx5_eswitch *esw,
1717 struct mlx5_vport *vport)
1718{
18486737
EB
1719 struct mlx5_flow_act flow_act = {0};
1720 struct mlx5_flow_spec *spec;
1721 int err = 0;
1722
1723 /* For prio tag mode, there is only 1 FTEs:
7445cfb1
JL
1724 * 1) Untagged packets - push prio tag VLAN and modify metadata if
1725 * required, allow
18486737
EB
1726 * Unmatched traffic is allowed by default
1727 */
1728
18486737
EB
1729 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1730 if (!spec) {
1731 err = -ENOMEM;
1732 goto out_no_mem;
1733 }
1734
1735 /* Untagged packets - push prio tag VLAN, allow */
1736 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1737 MLX5_SET(fte_match_param, spec->match_value, outer_headers.cvlan_tag, 0);
1738 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1739 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
1740 MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1741 flow_act.vlan[0].ethtype = ETH_P_8021Q;
1742 flow_act.vlan[0].vid = 0;
1743 flow_act.vlan[0].prio = 0;
7445cfb1
JL
1744
1745 if (vport->ingress.modify_metadata_rule) {
1746 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
1747 flow_act.modify_id = vport->ingress.modify_metadata_id;
1748 }
1749
18486737
EB
1750 vport->ingress.allow_rule =
1751 mlx5_add_flow_rules(vport->ingress.acl, spec,
1752 &flow_act, NULL, 0);
1753 if (IS_ERR(vport->ingress.allow_rule)) {
1754 err = PTR_ERR(vport->ingress.allow_rule);
1755 esw_warn(esw->dev,
1756 "vport[%d] configure ingress untagged allow rule, err(%d)\n",
1757 vport->vport, err);
1758 vport->ingress.allow_rule = NULL;
1759 goto out;
1760 }
1761
1762out:
1763 kvfree(spec);
1764out_no_mem:
1765 if (err)
1766 esw_vport_cleanup_ingress_rules(esw, vport);
1767 return err;
1768}
1769
7445cfb1
JL
1770static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
1771 struct mlx5_vport *vport)
1772{
1773 u8 action[MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto)] = {};
1774 struct mlx5_flow_act flow_act = {};
1775 struct mlx5_flow_spec spec = {};
1776 int err = 0;
1777
1778 MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
1779 MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_C_0);
1780 MLX5_SET(set_action_in, action, data,
1781 mlx5_eswitch_get_vport_metadata_for_match(esw, vport->vport));
1782
1783 err = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
1784 1, action, &vport->ingress.modify_metadata_id);
1785 if (err) {
1786 esw_warn(esw->dev,
1787 "failed to alloc modify header for vport %d ingress acl (%d)\n",
1788 vport->vport, err);
1789 return err;
1790 }
1791
1792 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1793 flow_act.modify_id = vport->ingress.modify_metadata_id;
1794 vport->ingress.modify_metadata_rule = mlx5_add_flow_rules(vport->ingress.acl,
1795 &spec, &flow_act, NULL, 0);
1796 if (IS_ERR(vport->ingress.modify_metadata_rule)) {
1797 err = PTR_ERR(vport->ingress.modify_metadata_rule);
1798 esw_warn(esw->dev,
1799 "failed to add setting metadata rule for vport %d ingress acl, err(%d)\n",
1800 vport->vport, err);
1801 vport->ingress.modify_metadata_rule = NULL;
1802 goto out;
1803 }
1804
1805out:
1806 if (err)
1807 mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
1808 return err;
1809}
1810
1811void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw,
1812 struct mlx5_vport *vport)
1813{
1814 if (vport->ingress.modify_metadata_rule) {
1815 mlx5_del_flow_rules(vport->ingress.modify_metadata_rule);
1816 mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata_id);
1817
1818 vport->ingress.modify_metadata_rule = NULL;
1819 }
1820}
1821
18486737
EB
1822static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw,
1823 struct mlx5_vport *vport)
1824{
1825 struct mlx5_flow_act flow_act = {0};
1826 struct mlx5_flow_spec *spec;
1827 int err = 0;
1828
7445cfb1
JL
1829 if (!MLX5_CAP_GEN(esw->dev, prio_tag_required))
1830 return 0;
1831
18486737
EB
1832 /* For prio tag mode, there is only 1 FTEs:
1833 * 1) prio tag packets - pop the prio tag VLAN, allow
1834 * Unmatched traffic is allowed by default
1835 */
1836
1837 esw_vport_cleanup_egress_rules(esw, vport);
1838
1839 err = esw_vport_enable_egress_acl(esw, vport);
1840 if (err) {
1841 mlx5_core_warn(esw->dev,
1842 "failed to enable egress acl (%d) on vport[%d]\n",
1843 err, vport->vport);
1844 return err;
1845 }
1846
1847 esw_debug(esw->dev,
1848 "vport[%d] configure prio tag egress rules\n", vport->vport);
1849
1850 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1851 if (!spec) {
1852 err = -ENOMEM;
1853 goto out_no_mem;
1854 }
1855
1856 /* prio tag vlan rule - pop it so VF receives untagged packets */
1857 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1858 MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
1859 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
1860 MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, 0);
1861
1862 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1863 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_VLAN_POP |
1864 MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1865 vport->egress.allowed_vlan =
1866 mlx5_add_flow_rules(vport->egress.acl, spec,
1867 &flow_act, NULL, 0);
1868 if (IS_ERR(vport->egress.allowed_vlan)) {
1869 err = PTR_ERR(vport->egress.allowed_vlan);
1870 esw_warn(esw->dev,
1871 "vport[%d] configure egress pop prio tag vlan rule failed, err(%d)\n",
1872 vport->vport, err);
1873 vport->egress.allowed_vlan = NULL;
1874 goto out;
1875 }
1876
1877out:
1878 kvfree(spec);
1879out_no_mem:
1880 if (err)
1881 esw_vport_cleanup_egress_rules(esw, vport);
1882 return err;
1883}
1884
7445cfb1
JL
1885static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw,
1886 struct mlx5_vport *vport)
18486737 1887{
18486737
EB
1888 int err;
1889
7445cfb1
JL
1890 if (!mlx5_eswitch_vport_match_metadata_enabled(esw) &&
1891 !MLX5_CAP_GEN(esw->dev, prio_tag_required))
1892 return 0;
1893
1894 esw_vport_cleanup_ingress_rules(esw, vport);
1895
1896 err = esw_vport_enable_ingress_acl(esw, vport);
1897 if (err) {
1898 esw_warn(esw->dev,
1899 "failed to enable ingress acl (%d) on vport[%d]\n",
1900 err, vport->vport);
1901 return err;
1902 }
1903
1904 esw_debug(esw->dev,
1905 "vport[%d] configure ingress rules\n", vport->vport);
1906
1907 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
1908 err = esw_vport_add_ingress_acl_modify_metadata(esw, vport);
1909 if (err)
1910 goto out;
1911 }
1912
1913 if (MLX5_CAP_GEN(esw->dev, prio_tag_required) &&
1914 mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
786ef904 1915 err = esw_vport_ingress_prio_tag_config(esw, vport);
18486737 1916 if (err)
7445cfb1
JL
1917 goto out;
1918 }
1919
1920out:
1921 if (err)
1922 esw_vport_disable_ingress_acl(esw, vport);
1923 return err;
1924}
1925
92ab1eb3
JL
1926static bool
1927esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
1928{
1929 if (!MLX5_CAP_ESW(esw->dev, esw_uplink_ingress_acl))
1930 return false;
1931
1932 if (!(MLX5_CAP_ESW_FLOWTABLE(esw->dev, fdb_to_vport_reg_c_id) &
1933 MLX5_FDB_TO_VPORT_REG_C_0))
1934 return false;
1935
1936 if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source))
1937 return false;
1938
1939 if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
1940 mlx5_ecpf_vport_exists(esw->dev))
1941 return false;
1942
1943 return true;
1944}
1945
7445cfb1
JL
1946static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw)
1947{
1948 struct mlx5_vport *vport;
1949 int i, j;
1950 int err;
1951
92ab1eb3
JL
1952 if (esw_check_vport_match_metadata_supported(esw))
1953 esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA;
1954
7445cfb1
JL
1955 mlx5_esw_for_all_vports(esw, i, vport) {
1956 err = esw_vport_ingress_common_config(esw, vport);
18486737 1957 if (err)
7445cfb1
JL
1958 goto err_ingress;
1959
1960 if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) {
1961 err = esw_vport_egress_prio_tag_config(esw, vport);
1962 if (err)
1963 goto err_egress;
1964 }
18486737
EB
1965 }
1966
7445cfb1
JL
1967 if (mlx5_eswitch_vport_match_metadata_enabled(esw))
1968 esw_info(esw->dev, "Use metadata reg_c as source vport to match\n");
1969
18486737
EB
1970 return 0;
1971
1972err_egress:
786ef904 1973 esw_vport_disable_ingress_acl(esw, vport);
18486737 1974err_ingress:
7445cfb1
JL
1975 for (j = MLX5_VPORT_PF; j < i; j++) {
1976 vport = &esw->vports[j];
786ef904
PP
1977 esw_vport_disable_egress_acl(esw, vport);
1978 esw_vport_disable_ingress_acl(esw, vport);
18486737
EB
1979 }
1980
1981 return err;
1982}
1983
7445cfb1 1984static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw)
18486737 1985{
786ef904 1986 struct mlx5_vport *vport;
18486737
EB
1987 int i;
1988
7445cfb1 1989 mlx5_esw_for_all_vports(esw, i, vport) {
786ef904
PP
1990 esw_vport_disable_egress_acl(esw, vport);
1991 esw_vport_disable_ingress_acl(esw, vport);
18486737 1992 }
7445cfb1
JL
1993
1994 esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA;
18486737
EB
1995}
1996
062f4bf4 1997static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
6ed1803a 1998{
062f4bf4
BW
1999 int num_vfs = esw->esw_funcs.num_vfs;
2000 int total_vports;
6ed1803a
MB
2001 int err;
2002
062f4bf4
BW
2003 if (mlx5_core_is_ecpf_esw_manager(esw->dev))
2004 total_vports = esw->total_vports;
2005 else
2006 total_vports = num_vfs + MLX5_SPECIAL_VPORTS(esw->dev);
2007
5c1d260e 2008 memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb));
e52c2802
PB
2009 mutex_init(&esw->fdb_table.offloads.fdb_prio_lock);
2010
7445cfb1
JL
2011 err = esw_create_offloads_acl_tables(esw);
2012 if (err)
2013 return err;
18486737 2014
062f4bf4 2015 err = esw_create_offloads_fdb_tables(esw, total_vports);
c930a3ad 2016 if (err)
7445cfb1 2017 goto create_fdb_err;
c930a3ad 2018
062f4bf4 2019 err = esw_create_offloads_table(esw, total_vports);
c930a3ad
OG
2020 if (err)
2021 goto create_ft_err;
2022
062f4bf4 2023 err = esw_create_vport_rx_group(esw, total_vports);
c930a3ad
OG
2024 if (err)
2025 goto create_fg_err;
2026
2027 return 0;
2028
2029create_fg_err:
2030 esw_destroy_offloads_table(esw);
2031
2032create_ft_err:
1967ce6e 2033 esw_destroy_offloads_fdb_tables(esw);
5bae8c03 2034
7445cfb1
JL
2035create_fdb_err:
2036 esw_destroy_offloads_acl_tables(esw);
2037
c930a3ad
OG
2038 return err;
2039}
2040
eca8cc38
BW
2041static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
2042{
2043 esw_destroy_vport_rx_group(esw);
2044 esw_destroy_offloads_table(esw);
2045 esw_destroy_offloads_fdb_tables(esw);
7445cfb1 2046 esw_destroy_offloads_acl_tables(esw);
eca8cc38
BW
2047}
2048
7e736f9a
PP
2049static void
2050esw_vfs_changed_event_handler(struct mlx5_eswitch *esw, const u32 *out)
a3888f33 2051{
5ccf2770 2052 bool host_pf_disabled;
7e736f9a 2053 u16 new_num_vfs;
a3888f33 2054
7e736f9a
PP
2055 new_num_vfs = MLX5_GET(query_esw_functions_out, out,
2056 host_params_context.host_num_of_vfs);
5ccf2770
BW
2057 host_pf_disabled = MLX5_GET(query_esw_functions_out, out,
2058 host_params_context.host_pf_disabled);
7e736f9a
PP
2059
2060 if (new_num_vfs == esw->esw_funcs.num_vfs || host_pf_disabled)
2061 return;
a3888f33
BW
2062
2063 /* Number of VFs can only change from "0 to x" or "x to 0". */
cd56f929
VP
2064 if (esw->esw_funcs.num_vfs > 0) {
2065 esw_offloads_unload_vf_reps(esw, esw->esw_funcs.num_vfs);
a3888f33 2066 } else {
7e736f9a 2067 int err;
a3888f33 2068
7e736f9a 2069 err = esw_offloads_load_vf_reps(esw, new_num_vfs);
a3888f33 2070 if (err)
7e736f9a 2071 return;
a3888f33 2072 }
7e736f9a
PP
2073 esw->esw_funcs.num_vfs = new_num_vfs;
2074}
2075
2076static void esw_functions_changed_event_handler(struct work_struct *work)
2077{
2078 u32 out[MLX5_ST_SZ_DW(query_esw_functions_out)] = {};
2079 struct mlx5_host_work *host_work;
2080 struct mlx5_eswitch *esw;
2081 int err;
2082
2083 host_work = container_of(work, struct mlx5_host_work, work);
2084 esw = host_work->esw;
a3888f33 2085
7e736f9a
PP
2086 err = mlx5_esw_query_functions(esw->dev, out, sizeof(out));
2087 if (err)
2088 goto out;
a3888f33 2089
7e736f9a 2090 esw_vfs_changed_event_handler(esw, out);
a3888f33
BW
2091out:
2092 kfree(host_work);
2093}
2094
16fff98a 2095int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data)
a3888f33 2096{
cd56f929 2097 struct mlx5_esw_functions *esw_funcs;
a3888f33 2098 struct mlx5_host_work *host_work;
a3888f33
BW
2099 struct mlx5_eswitch *esw;
2100
2101 host_work = kzalloc(sizeof(*host_work), GFP_ATOMIC);
2102 if (!host_work)
2103 return NOTIFY_DONE;
2104
cd56f929
VP
2105 esw_funcs = mlx5_nb_cof(nb, struct mlx5_esw_functions, nb);
2106 esw = container_of(esw_funcs, struct mlx5_eswitch, esw_funcs);
a3888f33
BW
2107
2108 host_work->esw = esw;
2109
062f4bf4 2110 INIT_WORK(&host_work->work, esw_functions_changed_event_handler);
a3888f33
BW
2111 queue_work(esw->work_queue, &host_work->work);
2112
2113 return NOTIFY_OK;
2114}
2115
062f4bf4 2116int esw_offloads_init(struct mlx5_eswitch *esw)
eca8cc38
BW
2117{
2118 int err;
2119
062f4bf4 2120 err = esw_offloads_steering_init(esw);
eca8cc38
BW
2121 if (err)
2122 return err;
2123
c1286050
JL
2124 if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
2125 err = mlx5_eswitch_enable_passing_vport_metadata(esw);
2126 if (err)
2127 goto err_vport_metadata;
2128 }
2129
062f4bf4 2130 err = esw_offloads_load_all_reps(esw);
eca8cc38
BW
2131 if (err)
2132 goto err_reps;
2133
2134 esw_offloads_devcom_init(esw);
a3888f33 2135
80f09dfc
MG
2136 mlx5_rdma_enable_roce(esw->dev);
2137
eca8cc38
BW
2138 return 0;
2139
2140err_reps:
c1286050
JL
2141 if (mlx5_eswitch_vport_match_metadata_enabled(esw))
2142 mlx5_eswitch_disable_passing_vport_metadata(esw);
2143err_vport_metadata:
eca8cc38
BW
2144 esw_offloads_steering_cleanup(esw);
2145 return err;
2146}
2147
db7ff19e
EB
2148static int esw_offloads_stop(struct mlx5_eswitch *esw,
2149 struct netlink_ext_ack *extack)
c930a3ad 2150{
062f4bf4 2151 int err, err1;
c930a3ad 2152
f6455de0 2153 mlx5_eswitch_disable(esw);
062f4bf4 2154 err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY);
6c419ba8 2155 if (err) {
8c98ee77 2156 NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
062f4bf4 2157 err1 = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS);
8c98ee77
EB
2158 if (err1) {
2159 NL_SET_ERR_MSG_MOD(extack,
2160 "Failed setting eswitch back to offloads");
2161 }
6c419ba8 2162 }
c930a3ad
OG
2163
2164 return err;
2165}
2166
c9b99abc 2167void esw_offloads_cleanup(struct mlx5_eswitch *esw)
c930a3ad 2168{
80f09dfc 2169 mlx5_rdma_disable_roce(esw->dev);
ac004b83 2170 esw_offloads_devcom_cleanup(esw);
062f4bf4 2171 esw_offloads_unload_all_reps(esw);
c1286050
JL
2172 if (mlx5_eswitch_vport_match_metadata_enabled(esw))
2173 mlx5_eswitch_disable_passing_vport_metadata(esw);
eca8cc38 2174 esw_offloads_steering_cleanup(esw);
c930a3ad
OG
2175}
2176
ef78618b 2177static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
c930a3ad
OG
2178{
2179 switch (mode) {
2180 case DEVLINK_ESWITCH_MODE_LEGACY:
f6455de0 2181 *mlx5_mode = MLX5_ESWITCH_LEGACY;
c930a3ad
OG
2182 break;
2183 case DEVLINK_ESWITCH_MODE_SWITCHDEV:
f6455de0 2184 *mlx5_mode = MLX5_ESWITCH_OFFLOADS;
c930a3ad
OG
2185 break;
2186 default:
2187 return -EINVAL;
2188 }
2189
2190 return 0;
2191}
2192
ef78618b
OG
2193static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
2194{
2195 switch (mlx5_mode) {
f6455de0 2196 case MLX5_ESWITCH_LEGACY:
ef78618b
OG
2197 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
2198 break;
f6455de0 2199 case MLX5_ESWITCH_OFFLOADS:
ef78618b
OG
2200 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
2201 break;
2202 default:
2203 return -EINVAL;
2204 }
2205
2206 return 0;
2207}
2208
bffaa916
RD
2209static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
2210{
2211 switch (mode) {
2212 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
2213 *mlx5_mode = MLX5_INLINE_MODE_NONE;
2214 break;
2215 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
2216 *mlx5_mode = MLX5_INLINE_MODE_L2;
2217 break;
2218 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
2219 *mlx5_mode = MLX5_INLINE_MODE_IP;
2220 break;
2221 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
2222 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
2223 break;
2224 default:
2225 return -EINVAL;
2226 }
2227
2228 return 0;
2229}
2230
2231static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
2232{
2233 switch (mlx5_mode) {
2234 case MLX5_INLINE_MODE_NONE:
2235 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
2236 break;
2237 case MLX5_INLINE_MODE_L2:
2238 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
2239 break;
2240 case MLX5_INLINE_MODE_IP:
2241 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
2242 break;
2243 case MLX5_INLINE_MODE_TCP_UDP:
2244 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
2245 break;
2246 default:
2247 return -EINVAL;
2248 }
2249
2250 return 0;
2251}
2252
9d1cef19 2253static int mlx5_devlink_eswitch_check(struct devlink *devlink)
feae9087 2254{
9d1cef19 2255 struct mlx5_core_dev *dev = devlink_priv(devlink);
c930a3ad 2256
9d1cef19
OG
2257 if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
2258 return -EOPNOTSUPP;
c930a3ad 2259
733d3e54
OG
2260 if(!MLX5_ESWITCH_MANAGER(dev))
2261 return -EPERM;
c930a3ad 2262
f6455de0 2263 if (dev->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
c96692fb 2264 !mlx5_core_is_ecpf_esw_manager(dev))
c930a3ad
OG
2265 return -EOPNOTSUPP;
2266
9d1cef19
OG
2267 return 0;
2268}
2269
db7ff19e
EB
2270int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
2271 struct netlink_ext_ack *extack)
9d1cef19
OG
2272{
2273 struct mlx5_core_dev *dev = devlink_priv(devlink);
2274 u16 cur_mlx5_mode, mlx5_mode = 0;
2275 int err;
2276
2277 err = mlx5_devlink_eswitch_check(devlink);
2278 if (err)
2279 return err;
2280
2281 cur_mlx5_mode = dev->priv.eswitch->mode;
2282
ef78618b 2283 if (esw_mode_from_devlink(mode, &mlx5_mode))
c930a3ad
OG
2284 return -EINVAL;
2285
2286 if (cur_mlx5_mode == mlx5_mode)
2287 return 0;
2288
2289 if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
db7ff19e 2290 return esw_offloads_start(dev->priv.eswitch, extack);
c930a3ad 2291 else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
db7ff19e 2292 return esw_offloads_stop(dev->priv.eswitch, extack);
c930a3ad
OG
2293 else
2294 return -EINVAL;
feae9087
OG
2295}
2296
2297int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
2298{
9d1cef19
OG
2299 struct mlx5_core_dev *dev = devlink_priv(devlink);
2300 int err;
c930a3ad 2301
9d1cef19
OG
2302 err = mlx5_devlink_eswitch_check(devlink);
2303 if (err)
2304 return err;
c930a3ad 2305
ef78618b 2306 return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
feae9087 2307}
127ea380 2308
db7ff19e
EB
2309int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
2310 struct netlink_ext_ack *extack)
bffaa916
RD
2311{
2312 struct mlx5_core_dev *dev = devlink_priv(devlink);
2313 struct mlx5_eswitch *esw = dev->priv.eswitch;
db68cc56 2314 int err, vport, num_vport;
bffaa916
RD
2315 u8 mlx5_mode;
2316
9d1cef19
OG
2317 err = mlx5_devlink_eswitch_check(devlink);
2318 if (err)
2319 return err;
bffaa916 2320
c415f704
OG
2321 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
2322 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
2323 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
2324 return 0;
2325 /* fall through */
2326 case MLX5_CAP_INLINE_MODE_L2:
8c98ee77 2327 NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
bffaa916 2328 return -EOPNOTSUPP;
c415f704
OG
2329 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
2330 break;
2331 }
bffaa916 2332
375f51e2 2333 if (esw->offloads.num_flows > 0) {
8c98ee77
EB
2334 NL_SET_ERR_MSG_MOD(extack,
2335 "Can't set inline mode when flows are configured");
375f51e2
RD
2336 return -EOPNOTSUPP;
2337 }
2338
bffaa916
RD
2339 err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
2340 if (err)
2341 goto out;
2342
411ec9e0 2343 mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
bffaa916
RD
2344 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
2345 if (err) {
8c98ee77
EB
2346 NL_SET_ERR_MSG_MOD(extack,
2347 "Failed to set min inline on vport");
bffaa916
RD
2348 goto revert_inline_mode;
2349 }
2350 }
2351
2352 esw->offloads.inline_mode = mlx5_mode;
2353 return 0;
2354
2355revert_inline_mode:
db68cc56 2356 num_vport = --vport;
411ec9e0 2357 mlx5_esw_for_each_host_func_vport_reverse(esw, vport, num_vport)
bffaa916
RD
2358 mlx5_modify_nic_vport_min_inline(dev,
2359 vport,
2360 esw->offloads.inline_mode);
2361out:
2362 return err;
2363}
2364
2365int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
2366{
2367 struct mlx5_core_dev *dev = devlink_priv(devlink);
2368 struct mlx5_eswitch *esw = dev->priv.eswitch;
9d1cef19 2369 int err;
bffaa916 2370
9d1cef19
OG
2371 err = mlx5_devlink_eswitch_check(devlink);
2372 if (err)
2373 return err;
bffaa916 2374
bffaa916
RD
2375 return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
2376}
2377
062f4bf4 2378int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
bffaa916 2379{
c415f704 2380 u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
bffaa916
RD
2381 struct mlx5_core_dev *dev = esw->dev;
2382 int vport;
bffaa916
RD
2383
2384 if (!MLX5_CAP_GEN(dev, vport_group_manager))
2385 return -EOPNOTSUPP;
2386
f6455de0 2387 if (esw->mode == MLX5_ESWITCH_NONE)
bffaa916
RD
2388 return -EOPNOTSUPP;
2389
c415f704
OG
2390 switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
2391 case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
2392 mlx5_mode = MLX5_INLINE_MODE_NONE;
2393 goto out;
2394 case MLX5_CAP_INLINE_MODE_L2:
2395 mlx5_mode = MLX5_INLINE_MODE_L2;
2396 goto out;
2397 case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
2398 goto query_vports;
2399 }
bffaa916 2400
c415f704 2401query_vports:
411ec9e0
BW
2402 mlx5_query_nic_vport_min_inline(dev, esw->first_host_vport, &prev_mlx5_mode);
2403 mlx5_esw_for_each_host_func_vport(esw, vport, esw->esw_funcs.num_vfs) {
bffaa916 2404 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
411ec9e0 2405 if (prev_mlx5_mode != mlx5_mode)
bffaa916
RD
2406 return -EINVAL;
2407 prev_mlx5_mode = mlx5_mode;
2408 }
2409
c415f704 2410out:
bffaa916
RD
2411 *mode = mlx5_mode;
2412 return 0;
2413}
2414
98fdbea5
LR
2415int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
2416 enum devlink_eswitch_encap_mode encap,
db7ff19e 2417 struct netlink_ext_ack *extack)
7768d197
RD
2418{
2419 struct mlx5_core_dev *dev = devlink_priv(devlink);
2420 struct mlx5_eswitch *esw = dev->priv.eswitch;
2421 int err;
2422
9d1cef19
OG
2423 err = mlx5_devlink_eswitch_check(devlink);
2424 if (err)
2425 return err;
7768d197
RD
2426
2427 if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
60786f09 2428 (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
7768d197
RD
2429 !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
2430 return -EOPNOTSUPP;
2431
2432 if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
2433 return -EOPNOTSUPP;
2434
f6455de0 2435 if (esw->mode == MLX5_ESWITCH_LEGACY) {
7768d197
RD
2436 esw->offloads.encap = encap;
2437 return 0;
2438 }
2439
2440 if (esw->offloads.encap == encap)
2441 return 0;
2442
2443 if (esw->offloads.num_flows > 0) {
8c98ee77
EB
2444 NL_SET_ERR_MSG_MOD(extack,
2445 "Can't set encapsulation when flows are configured");
7768d197
RD
2446 return -EOPNOTSUPP;
2447 }
2448
e52c2802 2449 esw_destroy_offloads_fdb_tables(esw);
7768d197
RD
2450
2451 esw->offloads.encap = encap;
e52c2802
PB
2452
2453 err = esw_create_offloads_fdb_tables(esw, esw->nvports);
2454
7768d197 2455 if (err) {
8c98ee77
EB
2456 NL_SET_ERR_MSG_MOD(extack,
2457 "Failed re-creating fast FDB table");
7768d197 2458 esw->offloads.encap = !encap;
e52c2802 2459 (void)esw_create_offloads_fdb_tables(esw, esw->nvports);
7768d197 2460 }
e52c2802 2461
7768d197
RD
2462 return err;
2463}
2464
98fdbea5
LR
2465int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
2466 enum devlink_eswitch_encap_mode *encap)
7768d197
RD
2467{
2468 struct mlx5_core_dev *dev = devlink_priv(devlink);
2469 struct mlx5_eswitch *esw = dev->priv.eswitch;
9d1cef19 2470 int err;
7768d197 2471
9d1cef19
OG
2472 err = mlx5_devlink_eswitch_check(devlink);
2473 if (err)
2474 return err;
7768d197
RD
2475
2476 *encap = esw->offloads.encap;
2477 return 0;
2478}
2479
f8e8fa02 2480void mlx5_eswitch_register_vport_reps(struct mlx5_eswitch *esw,
8693115a 2481 const struct mlx5_eswitch_rep_ops *ops,
f8e8fa02 2482 u8 rep_type)
127ea380 2483{
8693115a 2484 struct mlx5_eswitch_rep_data *rep_data;
f8e8fa02
BW
2485 struct mlx5_eswitch_rep *rep;
2486 int i;
9deb2241 2487
8693115a 2488 esw->offloads.rep_ops[rep_type] = ops;
f8e8fa02 2489 mlx5_esw_for_all_reps(esw, i, rep) {
8693115a
PP
2490 rep_data = &rep->rep_data[rep_type];
2491 atomic_set(&rep_data->state, REP_REGISTERED);
f8e8fa02 2492 }
127ea380 2493}
f8e8fa02 2494EXPORT_SYMBOL(mlx5_eswitch_register_vport_reps);
127ea380 2495
f8e8fa02 2496void mlx5_eswitch_unregister_vport_reps(struct mlx5_eswitch *esw, u8 rep_type)
127ea380 2497{
cb67b832 2498 struct mlx5_eswitch_rep *rep;
f8e8fa02 2499 int i;
cb67b832 2500
f6455de0 2501 if (esw->mode == MLX5_ESWITCH_OFFLOADS)
062f4bf4 2502 __unload_reps_all_vport(esw, rep_type);
127ea380 2503
f8e8fa02 2504 mlx5_esw_for_all_reps(esw, i, rep)
8693115a 2505 atomic_set(&rep->rep_data[rep_type].state, REP_UNREGISTERED);
127ea380 2506}
f8e8fa02 2507EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_reps);
726293f1 2508
a4b97ab4 2509void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
726293f1 2510{
726293f1
HHZ
2511 struct mlx5_eswitch_rep *rep;
2512
879c8f84 2513 rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK);
8693115a 2514 return rep->rep_data[rep_type].priv;
726293f1 2515}
22215908
MB
2516
2517void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
2518 int vport,
2519 u8 rep_type)
2520{
22215908
MB
2521 struct mlx5_eswitch_rep *rep;
2522
879c8f84 2523 rep = mlx5_eswitch_get_rep(esw, vport);
22215908 2524
8693115a
PP
2525 if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED &&
2526 esw->offloads.rep_ops[rep_type]->get_proto_dev)
2527 return esw->offloads.rep_ops[rep_type]->get_proto_dev(rep);
22215908
MB
2528 return NULL;
2529}
57cbd893 2530EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
22215908
MB
2531
2532void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
2533{
879c8f84 2534 return mlx5_eswitch_get_proto_dev(esw, MLX5_VPORT_UPLINK, rep_type);
22215908 2535}
57cbd893
MB
2536EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
2537
2538struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
2539 int vport)
2540{
879c8f84 2541 return mlx5_eswitch_get_rep(esw, vport);
57cbd893
MB
2542}
2543EXPORT_SYMBOL(mlx5_eswitch_vport_rep);
91d6291c
PP
2544
2545bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num)
2546{
2547 return vport_num >= MLX5_VPORT_FIRST_VF &&
2548 vport_num <= esw->dev->priv.sriov.max_vfs;
2549}
7445cfb1
JL
2550
2551bool mlx5_eswitch_vport_match_metadata_enabled(const struct mlx5_eswitch *esw)
2552{
2553 return !!(esw->flags & MLX5_ESWITCH_VPORT_MATCH_METADATA);
2554}
2555EXPORT_SYMBOL(mlx5_eswitch_vport_match_metadata_enabled);
2556
2557u32 mlx5_eswitch_get_vport_metadata_for_match(const struct mlx5_eswitch *esw,
2558 u16 vport_num)
2559{
2560 return ((MLX5_CAP_GEN(esw->dev, vhca_id) & 0xffff) << 16) | vport_num;
2561}
2562EXPORT_SYMBOL(mlx5_eswitch_get_vport_metadata_for_match);