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