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