]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
Merge branch 'mlx5-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux
[linux.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 "en.h"
41 #include "fs_core.h"
42 #include "lib/devcom.h"
43
44 enum {
45         FDB_FAST_PATH = 0,
46         FDB_SLOW_PATH
47 };
48
49 /* There are two match-all miss flows, one for unicast dst mac and
50  * one for multicast.
51  */
52 #define MLX5_ESW_MISS_FLOWS (2)
53
54 #define fdb_prio_table(esw, chain, prio, level) \
55         (esw)->fdb_table.offloads.fdb_prio[(chain)][(prio)][(level)]
56
57 static struct mlx5_flow_table *
58 esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
59 static void
60 esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level);
61
62 bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw)
63 {
64         return (!!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED));
65 }
66
67 u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw)
68 {
69         if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
70                 return FDB_MAX_CHAIN;
71
72         return 0;
73 }
74
75 u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw)
76 {
77         if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)
78                 return FDB_MAX_PRIO;
79
80         return 1;
81 }
82
83 struct mlx5_flow_handle *
84 mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
85                                 struct mlx5_flow_spec *spec,
86                                 struct mlx5_esw_flow_attr *attr)
87 {
88         struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
89         struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
90         bool split = !!(attr->split_count);
91         struct mlx5_flow_handle *rule;
92         struct mlx5_flow_table *fdb;
93         int j, i = 0;
94         void *misc;
95
96         if (esw->mode != SRIOV_OFFLOADS)
97                 return ERR_PTR(-EOPNOTSUPP);
98
99         flow_act.action = attr->action;
100         /* if per flow vlan pop/push is emulated, don't set that into the firmware */
101         if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
102                 flow_act.action &= ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
103                                      MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
104         else if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
105                 flow_act.vlan[0].ethtype = ntohs(attr->vlan_proto[0]);
106                 flow_act.vlan[0].vid = attr->vlan_vid[0];
107                 flow_act.vlan[0].prio = attr->vlan_prio[0];
108                 if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) {
109                         flow_act.vlan[1].ethtype = ntohs(attr->vlan_proto[1]);
110                         flow_act.vlan[1].vid = attr->vlan_vid[1];
111                         flow_act.vlan[1].prio = attr->vlan_prio[1];
112                 }
113         }
114
115         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
116                 if (attr->dest_chain) {
117                         struct mlx5_flow_table *ft;
118
119                         ft = esw_get_prio_table(esw, attr->dest_chain, 1, 0);
120                         if (IS_ERR(ft)) {
121                                 rule = ERR_CAST(ft);
122                                 goto err_create_goto_table;
123                         }
124
125                         dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
126                         dest[i].ft = ft;
127                         i++;
128                 } else {
129                         for (j = attr->split_count; j < attr->out_count; j++) {
130                                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
131                                 dest[i].vport.num = attr->dests[j].rep->vport;
132                                 dest[i].vport.vhca_id =
133                                         MLX5_CAP_GEN(attr->dests[j].mdev, vhca_id);
134                                 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
135                                         dest[i].vport.flags |=
136                                                 MLX5_FLOW_DEST_VPORT_VHCA_ID;
137                                 if (attr->dests[j].flags & MLX5_ESW_DEST_ENCAP) {
138                                         flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
139                                         flow_act.reformat_id = attr->dests[j].encap_id;
140                                         dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
141                                         dest[i].vport.reformat_id =
142                                                 attr->dests[j].encap_id;
143                                 }
144                                 i++;
145                         }
146                 }
147         }
148         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
149                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
150                 dest[i].counter_id = mlx5_fc_id(attr->counter);
151                 i++;
152         }
153
154         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
155         MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
156
157         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
158                 MLX5_SET(fte_match_set_misc, misc,
159                          source_eswitch_owner_vhca_id,
160                          MLX5_CAP_GEN(attr->in_mdev, vhca_id));
161
162         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
163         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
164         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
165                 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
166                                  source_eswitch_owner_vhca_id);
167
168         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
169         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) {
170                 if (attr->tunnel_match_level != MLX5_MATCH_NONE)
171                         spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
172                 if (attr->match_level != MLX5_MATCH_NONE)
173                         spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
174         } else if (attr->match_level != MLX5_MATCH_NONE) {
175                 spec->match_criteria_enable |= MLX5_MATCH_OUTER_HEADERS;
176         }
177
178         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
179                 flow_act.modify_id = attr->mod_hdr_id;
180
181         fdb = esw_get_prio_table(esw, attr->chain, attr->prio, !!split);
182         if (IS_ERR(fdb)) {
183                 rule = ERR_CAST(fdb);
184                 goto err_esw_get;
185         }
186
187         rule = mlx5_add_flow_rules(fdb, spec, &flow_act, dest, i);
188         if (IS_ERR(rule))
189                 goto err_add_rule;
190         else
191                 esw->offloads.num_flows++;
192
193         return rule;
194
195 err_add_rule:
196         esw_put_prio_table(esw, attr->chain, attr->prio, !!split);
197 err_esw_get:
198         if (attr->dest_chain)
199                 esw_put_prio_table(esw, attr->dest_chain, 1, 0);
200 err_create_goto_table:
201         return rule;
202 }
203
204 struct mlx5_flow_handle *
205 mlx5_eswitch_add_fwd_rule(struct mlx5_eswitch *esw,
206                           struct mlx5_flow_spec *spec,
207                           struct mlx5_esw_flow_attr *attr)
208 {
209         struct mlx5_flow_destination dest[MLX5_MAX_FLOW_FWD_VPORTS + 1] = {};
210         struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND, };
211         struct mlx5_flow_table *fast_fdb;
212         struct mlx5_flow_table *fwd_fdb;
213         struct mlx5_flow_handle *rule;
214         void *misc;
215         int i;
216
217         fast_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 0);
218         if (IS_ERR(fast_fdb)) {
219                 rule = ERR_CAST(fast_fdb);
220                 goto err_get_fast;
221         }
222
223         fwd_fdb = esw_get_prio_table(esw, attr->chain, attr->prio, 1);
224         if (IS_ERR(fwd_fdb)) {
225                 rule = ERR_CAST(fwd_fdb);
226                 goto err_get_fwd;
227         }
228
229         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
230         for (i = 0; i < attr->split_count; i++) {
231                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
232                 dest[i].vport.num = attr->dests[i].rep->vport;
233                 dest[i].vport.vhca_id =
234                         MLX5_CAP_GEN(attr->dests[i].mdev, vhca_id);
235                 if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
236                         dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
237                 if (attr->dests[i].flags & MLX5_ESW_DEST_ENCAP) {
238                         dest[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
239                         dest[i].vport.reformat_id = attr->dests[i].encap_id;
240                 }
241         }
242         dest[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
243         dest[i].ft = fwd_fdb,
244         i++;
245
246         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
247         MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
248
249         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
250                 MLX5_SET(fte_match_set_misc, misc,
251                          source_eswitch_owner_vhca_id,
252                          MLX5_CAP_GEN(attr->in_mdev, vhca_id));
253
254         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
255         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
256         if (MLX5_CAP_ESW(esw->dev, merged_eswitch))
257                 MLX5_SET_TO_ONES(fte_match_set_misc, misc,
258                                  source_eswitch_owner_vhca_id);
259
260         if (attr->match_level == MLX5_MATCH_NONE)
261                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
262         else
263                 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
264                                               MLX5_MATCH_MISC_PARAMETERS;
265
266         rule = mlx5_add_flow_rules(fast_fdb, spec, &flow_act, dest, i);
267
268         if (IS_ERR(rule))
269                 goto add_err;
270
271         esw->offloads.num_flows++;
272
273         return rule;
274 add_err:
275         esw_put_prio_table(esw, attr->chain, attr->prio, 1);
276 err_get_fwd:
277         esw_put_prio_table(esw, attr->chain, attr->prio, 0);
278 err_get_fast:
279         return rule;
280 }
281
282 static void
283 __mlx5_eswitch_del_rule(struct mlx5_eswitch *esw,
284                         struct mlx5_flow_handle *rule,
285                         struct mlx5_esw_flow_attr *attr,
286                         bool fwd_rule)
287 {
288         bool split = (attr->split_count > 0);
289
290         mlx5_del_flow_rules(rule);
291         esw->offloads.num_flows--;
292
293         if (fwd_rule)  {
294                 esw_put_prio_table(esw, attr->chain, attr->prio, 1);
295                 esw_put_prio_table(esw, attr->chain, attr->prio, 0);
296         } else {
297                 esw_put_prio_table(esw, attr->chain, attr->prio, !!split);
298                 if (attr->dest_chain)
299                         esw_put_prio_table(esw, attr->dest_chain, 1, 0);
300         }
301 }
302
303 void
304 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
305                                 struct mlx5_flow_handle *rule,
306                                 struct mlx5_esw_flow_attr *attr)
307 {
308         __mlx5_eswitch_del_rule(esw, rule, attr, false);
309 }
310
311 void
312 mlx5_eswitch_del_fwd_rule(struct mlx5_eswitch *esw,
313                           struct mlx5_flow_handle *rule,
314                           struct mlx5_esw_flow_attr *attr)
315 {
316         __mlx5_eswitch_del_rule(esw, rule, attr, true);
317 }
318
319 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
320 {
321         struct mlx5_eswitch_rep *rep;
322         int vf_vport, err = 0;
323
324         esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
325         for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
326                 rep = &esw->offloads.vport_reps[vf_vport];
327                 if (!rep->rep_if[REP_ETH].valid)
328                         continue;
329
330                 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
331                 if (err)
332                         goto out;
333         }
334
335 out:
336         return err;
337 }
338
339 static struct mlx5_eswitch_rep *
340 esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
341 {
342         struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
343
344         in_rep  = attr->in_rep;
345         out_rep = attr->dests[0].rep;
346
347         if (push)
348                 vport = in_rep;
349         else if (pop)
350                 vport = out_rep;
351         else
352                 vport = in_rep;
353
354         return vport;
355 }
356
357 static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
358                                      bool push, bool pop, bool fwd)
359 {
360         struct mlx5_eswitch_rep *in_rep, *out_rep;
361
362         if ((push || pop) && !fwd)
363                 goto out_notsupp;
364
365         in_rep  = attr->in_rep;
366         out_rep = attr->dests[0].rep;
367
368         if (push && in_rep->vport == MLX5_VPORT_UPLINK)
369                 goto out_notsupp;
370
371         if (pop && out_rep->vport == MLX5_VPORT_UPLINK)
372                 goto out_notsupp;
373
374         /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
375         if (!push && !pop && fwd)
376                 if (in_rep->vlan && out_rep->vport == MLX5_VPORT_UPLINK)
377                         goto out_notsupp;
378
379         /* protects against (1) setting rules with different vlans to push and
380          * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
381          */
382         if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid[0]))
383                 goto out_notsupp;
384
385         return 0;
386
387 out_notsupp:
388         return -EOPNOTSUPP;
389 }
390
391 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
392                                  struct mlx5_esw_flow_attr *attr)
393 {
394         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
395         struct mlx5_eswitch_rep *vport = NULL;
396         bool push, pop, fwd;
397         int err = 0;
398
399         /* nop if we're on the vlan push/pop non emulation mode */
400         if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
401                 return 0;
402
403         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
404         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
405         fwd  = !!((attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
406                    !attr->dest_chain);
407
408         err = esw_add_vlan_action_check(attr, push, pop, fwd);
409         if (err)
410                 return err;
411
412         attr->vlan_handled = false;
413
414         vport = esw_vlan_action_get_vport(attr, push, pop);
415
416         if (!push && !pop && fwd) {
417                 /* tracks VF --> wire rules without vlan push action */
418                 if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK) {
419                         vport->vlan_refcount++;
420                         attr->vlan_handled = true;
421                 }
422
423                 return 0;
424         }
425
426         if (!push && !pop)
427                 return 0;
428
429         if (!(offloads->vlan_push_pop_refcount)) {
430                 /* it's the 1st vlan rule, apply global vlan pop policy */
431                 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
432                 if (err)
433                         goto out;
434         }
435         offloads->vlan_push_pop_refcount++;
436
437         if (push) {
438                 if (vport->vlan_refcount)
439                         goto skip_set_push;
440
441                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan_vid[0], 0,
442                                                     SET_VLAN_INSERT | SET_VLAN_STRIP);
443                 if (err)
444                         goto out;
445                 vport->vlan = attr->vlan_vid[0];
446 skip_set_push:
447                 vport->vlan_refcount++;
448         }
449 out:
450         if (!err)
451                 attr->vlan_handled = true;
452         return err;
453 }
454
455 int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
456                                  struct mlx5_esw_flow_attr *attr)
457 {
458         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
459         struct mlx5_eswitch_rep *vport = NULL;
460         bool push, pop, fwd;
461         int err = 0;
462
463         /* nop if we're on the vlan push/pop non emulation mode */
464         if (mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
465                 return 0;
466
467         if (!attr->vlan_handled)
468                 return 0;
469
470         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
471         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
472         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
473
474         vport = esw_vlan_action_get_vport(attr, push, pop);
475
476         if (!push && !pop && fwd) {
477                 /* tracks VF --> wire rules without vlan push action */
478                 if (attr->dests[0].rep->vport == MLX5_VPORT_UPLINK)
479                         vport->vlan_refcount--;
480
481                 return 0;
482         }
483
484         if (push) {
485                 vport->vlan_refcount--;
486                 if (vport->vlan_refcount)
487                         goto skip_unset_push;
488
489                 vport->vlan = 0;
490                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
491                                                     0, 0, SET_VLAN_STRIP);
492                 if (err)
493                         goto out;
494         }
495
496 skip_unset_push:
497         offloads->vlan_push_pop_refcount--;
498         if (offloads->vlan_push_pop_refcount)
499                 return 0;
500
501         /* no more vlan rules, stop global vlan pop policy */
502         err = esw_set_global_vlan_pop(esw, 0);
503
504 out:
505         return err;
506 }
507
508 struct mlx5_flow_handle *
509 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn)
510 {
511         struct mlx5_flow_act flow_act = {0};
512         struct mlx5_flow_destination dest = {};
513         struct mlx5_flow_handle *flow_rule;
514         struct mlx5_flow_spec *spec;
515         void *misc;
516
517         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
518         if (!spec) {
519                 flow_rule = ERR_PTR(-ENOMEM);
520                 goto out;
521         }
522
523         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
524         MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
525         MLX5_SET(fte_match_set_misc, misc, source_port, 0x0); /* source vport is 0 */
526
527         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
528         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
529         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
530
531         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
532         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
533         dest.vport.num = vport;
534         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
535
536         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
537                                         &flow_act, &dest, 1);
538         if (IS_ERR(flow_rule))
539                 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
540 out:
541         kvfree(spec);
542         return flow_rule;
543 }
544 EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
545
546 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
547 {
548         mlx5_del_flow_rules(rule);
549 }
550
551 static void peer_miss_rules_setup(struct mlx5_core_dev *peer_dev,
552                                   struct mlx5_flow_spec *spec,
553                                   struct mlx5_flow_destination *dest)
554 {
555         void *misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
556                                   misc_parameters);
557
558         MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id,
559                  MLX5_CAP_GEN(peer_dev, vhca_id));
560
561         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
562
563         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
564                             misc_parameters);
565         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
566         MLX5_SET_TO_ONES(fte_match_set_misc, misc,
567                          source_eswitch_owner_vhca_id);
568
569         dest->type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
570         dest->vport.num = 0;
571         dest->vport.vhca_id = MLX5_CAP_GEN(peer_dev, vhca_id);
572         dest->vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
573 }
574
575 static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw,
576                                        struct mlx5_core_dev *peer_dev)
577 {
578         struct mlx5_flow_destination dest = {};
579         struct mlx5_flow_act flow_act = {0};
580         struct mlx5_flow_handle **flows;
581         struct mlx5_flow_handle *flow;
582         struct mlx5_flow_spec *spec;
583         /* total vports is the same for both e-switches */
584         int nvports = esw->total_vports;
585         void *misc;
586         int err, i;
587
588         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
589         if (!spec)
590                 return -ENOMEM;
591
592         peer_miss_rules_setup(peer_dev, spec, &dest);
593
594         flows = kvzalloc(nvports * sizeof(*flows), GFP_KERNEL);
595         if (!flows) {
596                 err = -ENOMEM;
597                 goto alloc_flows_err;
598         }
599
600         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
601         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
602                             misc_parameters);
603
604         for (i = 1; i < nvports; i++) {
605                 MLX5_SET(fte_match_set_misc, misc, source_port, i);
606                 flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb,
607                                            spec, &flow_act, &dest, 1);
608                 if (IS_ERR(flow)) {
609                         err = PTR_ERR(flow);
610                         esw_warn(esw->dev, "FDB: Failed to add peer miss flow rule err %d\n", err);
611                         goto add_flow_err;
612                 }
613                 flows[i] = flow;
614         }
615
616         esw->fdb_table.offloads.peer_miss_rules = flows;
617
618         kvfree(spec);
619         return 0;
620
621 add_flow_err:
622         for (i--; i > 0; i--)
623                 mlx5_del_flow_rules(flows[i]);
624         kvfree(flows);
625 alloc_flows_err:
626         kvfree(spec);
627         return err;
628 }
629
630 static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw)
631 {
632         struct mlx5_flow_handle **flows;
633         int i;
634
635         flows = esw->fdb_table.offloads.peer_miss_rules;
636
637         for (i = 1; i < esw->total_vports; i++)
638                 mlx5_del_flow_rules(flows[i]);
639
640         kvfree(flows);
641 }
642
643 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
644 {
645         struct mlx5_flow_act flow_act = {0};
646         struct mlx5_flow_destination dest = {};
647         struct mlx5_flow_handle *flow_rule = NULL;
648         struct mlx5_flow_spec *spec;
649         void *headers_c;
650         void *headers_v;
651         int err = 0;
652         u8 *dmac_c;
653         u8 *dmac_v;
654
655         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
656         if (!spec) {
657                 err = -ENOMEM;
658                 goto out;
659         }
660
661         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
662         headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
663                                  outer_headers);
664         dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
665                               outer_headers.dmac_47_16);
666         dmac_c[0] = 0x01;
667
668         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
669         dest.vport.num = 0;
670         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
671
672         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
673                                         &flow_act, &dest, 1);
674         if (IS_ERR(flow_rule)) {
675                 err = PTR_ERR(flow_rule);
676                 esw_warn(esw->dev,  "FDB: Failed to add unicast miss flow rule err %d\n", err);
677                 goto out;
678         }
679
680         esw->fdb_table.offloads.miss_rule_uni = flow_rule;
681
682         headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
683                                  outer_headers);
684         dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
685                               outer_headers.dmac_47_16);
686         dmac_v[0] = 0x01;
687         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, spec,
688                                         &flow_act, &dest, 1);
689         if (IS_ERR(flow_rule)) {
690                 err = PTR_ERR(flow_rule);
691                 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
692                 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
693                 goto out;
694         }
695
696         esw->fdb_table.offloads.miss_rule_multi = flow_rule;
697
698 out:
699         kvfree(spec);
700         return err;
701 }
702
703 #define ESW_OFFLOADS_NUM_GROUPS  4
704
705 /* Firmware currently has 4 pool of 4 sizes that it supports (ESW_POOLS),
706  * and a virtual memory region of 16M (ESW_SIZE), this region is duplicated
707  * for each flow table pool. We can allocate up to 16M of each pool,
708  * and we keep track of how much we used via put/get_sz_to_pool.
709  * Firmware doesn't report any of this for now.
710  * ESW_POOL is expected to be sorted from large to small
711  */
712 #define ESW_SIZE (16 * 1024 * 1024)
713 const unsigned int ESW_POOLS[4] = { 4 * 1024 * 1024, 1 * 1024 * 1024,
714                                     64 * 1024, 4 * 1024 };
715
716 static int
717 get_sz_from_pool(struct mlx5_eswitch *esw)
718 {
719         int sz = 0, i;
720
721         for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
722                 if (esw->fdb_table.offloads.fdb_left[i]) {
723                         --esw->fdb_table.offloads.fdb_left[i];
724                         sz = ESW_POOLS[i];
725                         break;
726                 }
727         }
728
729         return sz;
730 }
731
732 static void
733 put_sz_to_pool(struct mlx5_eswitch *esw, int sz)
734 {
735         int i;
736
737         for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++) {
738                 if (sz >= ESW_POOLS[i]) {
739                         ++esw->fdb_table.offloads.fdb_left[i];
740                         break;
741                 }
742         }
743 }
744
745 static struct mlx5_flow_table *
746 create_next_size_table(struct mlx5_eswitch *esw,
747                        struct mlx5_flow_namespace *ns,
748                        u16 table_prio,
749                        int level,
750                        u32 flags)
751 {
752         struct mlx5_flow_table *fdb;
753         int sz;
754
755         sz = get_sz_from_pool(esw);
756         if (!sz)
757                 return ERR_PTR(-ENOSPC);
758
759         fdb = mlx5_create_auto_grouped_flow_table(ns,
760                                                   table_prio,
761                                                   sz,
762                                                   ESW_OFFLOADS_NUM_GROUPS,
763                                                   level,
764                                                   flags);
765         if (IS_ERR(fdb)) {
766                 esw_warn(esw->dev, "Failed to create FDB Table err %d (table prio: %d, level: %d, size: %d)\n",
767                          (int)PTR_ERR(fdb), table_prio, level, sz);
768                 put_sz_to_pool(esw, sz);
769         }
770
771         return fdb;
772 }
773
774 static struct mlx5_flow_table *
775 esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
776 {
777         struct mlx5_core_dev *dev = esw->dev;
778         struct mlx5_flow_table *fdb = NULL;
779         struct mlx5_flow_namespace *ns;
780         int table_prio, l = 0;
781         u32 flags = 0;
782
783         if (chain == FDB_SLOW_PATH_CHAIN)
784                 return esw->fdb_table.offloads.slow_fdb;
785
786         mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
787
788         fdb = fdb_prio_table(esw, chain, prio, level).fdb;
789         if (fdb) {
790                 /* take ref on earlier levels as well */
791                 while (level >= 0)
792                         fdb_prio_table(esw, chain, prio, level--).num_rules++;
793                 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
794                 return fdb;
795         }
796
797         ns = mlx5_get_fdb_sub_ns(dev, chain);
798         if (!ns) {
799                 esw_warn(dev, "Failed to get FDB sub namespace\n");
800                 mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
801                 return ERR_PTR(-EOPNOTSUPP);
802         }
803
804         if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
805                 flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
806                           MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
807
808         table_prio = (chain * FDB_MAX_PRIO) + prio - 1;
809
810         /* create earlier levels for correct fs_core lookup when
811          * connecting tables
812          */
813         for (l = 0; l <= level; l++) {
814                 if (fdb_prio_table(esw, chain, prio, l).fdb) {
815                         fdb_prio_table(esw, chain, prio, l).num_rules++;
816                         continue;
817                 }
818
819                 fdb = create_next_size_table(esw, ns, table_prio, l, flags);
820                 if (IS_ERR(fdb)) {
821                         l--;
822                         goto err_create_fdb;
823                 }
824
825                 fdb_prio_table(esw, chain, prio, l).fdb = fdb;
826                 fdb_prio_table(esw, chain, prio, l).num_rules = 1;
827         }
828
829         mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
830         return fdb;
831
832 err_create_fdb:
833         mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
834         if (l >= 0)
835                 esw_put_prio_table(esw, chain, prio, l);
836
837         return fdb;
838 }
839
840 static void
841 esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level)
842 {
843         int l;
844
845         if (chain == FDB_SLOW_PATH_CHAIN)
846                 return;
847
848         mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock);
849
850         for (l = level; l >= 0; l--) {
851                 if (--(fdb_prio_table(esw, chain, prio, l).num_rules) > 0)
852                         continue;
853
854                 put_sz_to_pool(esw, fdb_prio_table(esw, chain, prio, l).fdb->max_fte);
855                 mlx5_destroy_flow_table(fdb_prio_table(esw, chain, prio, l).fdb);
856                 fdb_prio_table(esw, chain, prio, l).fdb = NULL;
857         }
858
859         mutex_unlock(&esw->fdb_table.offloads.fdb_prio_lock);
860 }
861
862 static void esw_destroy_offloads_fast_fdb_tables(struct mlx5_eswitch *esw)
863 {
864         /* If lazy creation isn't supported, deref the fast path tables */
865         if (!(esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED)) {
866                 esw_put_prio_table(esw, 0, 1, 1);
867                 esw_put_prio_table(esw, 0, 1, 0);
868         }
869 }
870
871 #define MAX_PF_SQ 256
872 #define MAX_SQ_NVPORTS 32
873
874 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
875 {
876         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
877         struct mlx5_flow_table_attr ft_attr = {};
878         struct mlx5_core_dev *dev = esw->dev;
879         u32 *flow_group_in, max_flow_counter;
880         struct mlx5_flow_namespace *root_ns;
881         struct mlx5_flow_table *fdb = NULL;
882         int table_size, ix, err = 0, i;
883         struct mlx5_flow_group *g;
884         u32 flags = 0, fdb_max;
885         void *match_criteria;
886         u8 *dmac;
887
888         esw_debug(esw->dev, "Create offloads FDB Tables\n");
889         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
890         if (!flow_group_in)
891                 return -ENOMEM;
892
893         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
894         if (!root_ns) {
895                 esw_warn(dev, "Failed to get FDB flow namespace\n");
896                 err = -EOPNOTSUPP;
897                 goto ns_err;
898         }
899
900         max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
901                             MLX5_CAP_GEN(dev, max_flow_counter_15_0);
902         fdb_max = 1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size);
903
904         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",
905                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
906                   max_flow_counter, ESW_OFFLOADS_NUM_GROUPS,
907                   fdb_max);
908
909         for (i = 0; i < ARRAY_SIZE(ESW_POOLS); i++)
910                 esw->fdb_table.offloads.fdb_left[i] =
911                         ESW_POOLS[i] <= fdb_max ? ESW_SIZE / ESW_POOLS[i] : 0;
912
913         table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ +
914                 MLX5_ESW_MISS_FLOWS + esw->total_vports;
915
916         /* create the slow path fdb with encap set, so further table instances
917          * can be created at run time while VFs are probed if the FW allows that.
918          */
919         if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
920                 flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT |
921                           MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
922
923         ft_attr.flags = flags;
924         ft_attr.max_fte = table_size;
925         ft_attr.prio = FDB_SLOW_PATH;
926
927         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
928         if (IS_ERR(fdb)) {
929                 err = PTR_ERR(fdb);
930                 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
931                 goto slow_fdb_err;
932         }
933         esw->fdb_table.offloads.slow_fdb = fdb;
934
935         /* If lazy creation isn't supported, open the fast path tables now */
936         if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, multi_fdb_encap) &&
937             esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE) {
938                 esw->fdb_table.flags &= ~ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
939                 esw_warn(dev, "Lazy creation of flow tables isn't supported, ignoring priorities\n");
940                 esw_get_prio_table(esw, 0, 1, 0);
941                 esw_get_prio_table(esw, 0, 1, 1);
942         } else {
943                 esw_debug(dev, "Lazy creation of flow tables supported, deferring table opening\n");
944                 esw->fdb_table.flags |= ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED;
945         }
946
947         /* create send-to-vport group */
948         memset(flow_group_in, 0, inlen);
949         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
950                  MLX5_MATCH_MISC_PARAMETERS);
951
952         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
953
954         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
955         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
956
957         ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
958         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
959         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
960
961         g = mlx5_create_flow_group(fdb, flow_group_in);
962         if (IS_ERR(g)) {
963                 err = PTR_ERR(g);
964                 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
965                 goto send_vport_err;
966         }
967         esw->fdb_table.offloads.send_to_vport_grp = g;
968
969         /* create peer esw miss group */
970         memset(flow_group_in, 0, inlen);
971         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
972                  MLX5_MATCH_MISC_PARAMETERS);
973
974         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
975                                       match_criteria);
976
977         MLX5_SET_TO_ONES(fte_match_param, match_criteria,
978                          misc_parameters.source_port);
979         MLX5_SET_TO_ONES(fte_match_param, match_criteria,
980                          misc_parameters.source_eswitch_owner_vhca_id);
981
982         MLX5_SET(create_flow_group_in, flow_group_in,
983                  source_eswitch_owner_vhca_id_valid, 1);
984         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
985         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
986                  ix + esw->total_vports - 1);
987         ix += esw->total_vports;
988
989         g = mlx5_create_flow_group(fdb, flow_group_in);
990         if (IS_ERR(g)) {
991                 err = PTR_ERR(g);
992                 esw_warn(dev, "Failed to create peer miss flow group err(%d)\n", err);
993                 goto peer_miss_err;
994         }
995         esw->fdb_table.offloads.peer_miss_grp = g;
996
997         /* create miss group */
998         memset(flow_group_in, 0, inlen);
999         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1000                  MLX5_MATCH_OUTER_HEADERS);
1001         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
1002                                       match_criteria);
1003         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
1004                             outer_headers.dmac_47_16);
1005         dmac[0] = 0x01;
1006
1007         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
1008         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index,
1009                  ix + MLX5_ESW_MISS_FLOWS);
1010
1011         g = mlx5_create_flow_group(fdb, flow_group_in);
1012         if (IS_ERR(g)) {
1013                 err = PTR_ERR(g);
1014                 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
1015                 goto miss_err;
1016         }
1017         esw->fdb_table.offloads.miss_grp = g;
1018
1019         err = esw_add_fdb_miss_rule(esw);
1020         if (err)
1021                 goto miss_rule_err;
1022
1023         esw->nvports = nvports;
1024         kvfree(flow_group_in);
1025         return 0;
1026
1027 miss_rule_err:
1028         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1029 miss_err:
1030         mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1031 peer_miss_err:
1032         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1033 send_vport_err:
1034         esw_destroy_offloads_fast_fdb_tables(esw);
1035         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
1036 slow_fdb_err:
1037 ns_err:
1038         kvfree(flow_group_in);
1039         return err;
1040 }
1041
1042 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
1043 {
1044         if (!esw->fdb_table.offloads.slow_fdb)
1045                 return;
1046
1047         esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
1048         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
1049         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
1050         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
1051         mlx5_destroy_flow_group(esw->fdb_table.offloads.peer_miss_grp);
1052         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
1053
1054         mlx5_destroy_flow_table(esw->fdb_table.offloads.slow_fdb);
1055         esw_destroy_offloads_fast_fdb_tables(esw);
1056 }
1057
1058 static int esw_create_offloads_table(struct mlx5_eswitch *esw, int nvports)
1059 {
1060         struct mlx5_flow_table_attr ft_attr = {};
1061         struct mlx5_core_dev *dev = esw->dev;
1062         struct mlx5_flow_table *ft_offloads;
1063         struct mlx5_flow_namespace *ns;
1064         int err = 0;
1065
1066         ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
1067         if (!ns) {
1068                 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
1069                 return -EOPNOTSUPP;
1070         }
1071
1072         ft_attr.max_fte = nvports + MLX5_ESW_MISS_FLOWS;
1073
1074         ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
1075         if (IS_ERR(ft_offloads)) {
1076                 err = PTR_ERR(ft_offloads);
1077                 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
1078                 return err;
1079         }
1080
1081         esw->offloads.ft_offloads = ft_offloads;
1082         return 0;
1083 }
1084
1085 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
1086 {
1087         struct mlx5_esw_offload *offloads = &esw->offloads;
1088
1089         mlx5_destroy_flow_table(offloads->ft_offloads);
1090 }
1091
1092 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw, int nvports)
1093 {
1094         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1095         struct mlx5_flow_group *g;
1096         u32 *flow_group_in;
1097         void *match_criteria, *misc;
1098         int err = 0;
1099
1100         nvports = nvports + MLX5_ESW_MISS_FLOWS;
1101         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1102         if (!flow_group_in)
1103                 return -ENOMEM;
1104
1105         /* create vport rx group */
1106         memset(flow_group_in, 0, inlen);
1107         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
1108                  MLX5_MATCH_MISC_PARAMETERS);
1109
1110         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1111         misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
1112         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1113
1114         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1115         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
1116
1117         g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
1118
1119         if (IS_ERR(g)) {
1120                 err = PTR_ERR(g);
1121                 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
1122                 goto out;
1123         }
1124
1125         esw->offloads.vport_rx_group = g;
1126 out:
1127         kvfree(flow_group_in);
1128         return err;
1129 }
1130
1131 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
1132 {
1133         mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
1134 }
1135
1136 struct mlx5_flow_handle *
1137 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport,
1138                                   struct mlx5_flow_destination *dest)
1139 {
1140         struct mlx5_flow_act flow_act = {0};
1141         struct mlx5_flow_handle *flow_rule;
1142         struct mlx5_flow_spec *spec;
1143         void *misc;
1144
1145         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1146         if (!spec) {
1147                 flow_rule = ERR_PTR(-ENOMEM);
1148                 goto out;
1149         }
1150
1151         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
1152         MLX5_SET(fte_match_set_misc, misc, source_port, vport);
1153
1154         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
1155         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
1156
1157         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
1158
1159         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
1160         flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
1161                                         &flow_act, dest, 1);
1162         if (IS_ERR(flow_rule)) {
1163                 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
1164                 goto out;
1165         }
1166
1167 out:
1168         kvfree(spec);
1169         return flow_rule;
1170 }
1171
1172 static int esw_offloads_start(struct mlx5_eswitch *esw,
1173                               struct netlink_ext_ack *extack)
1174 {
1175         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
1176
1177         if (esw->mode != SRIOV_LEGACY) {
1178                 NL_SET_ERR_MSG_MOD(extack,
1179                                    "Can't set offloads mode, SRIOV legacy not enabled");
1180                 return -EINVAL;
1181         }
1182
1183         mlx5_eswitch_disable_sriov(esw);
1184         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
1185         if (err) {
1186                 NL_SET_ERR_MSG_MOD(extack,
1187                                    "Failed setting eswitch to offloads");
1188                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
1189                 if (err1) {
1190                         NL_SET_ERR_MSG_MOD(extack,
1191                                            "Failed setting eswitch back to legacy");
1192                 }
1193         }
1194         if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
1195                 if (mlx5_eswitch_inline_mode_get(esw,
1196                                                  num_vfs,
1197                                                  &esw->offloads.inline_mode)) {
1198                         esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
1199                         NL_SET_ERR_MSG_MOD(extack,
1200                                            "Inline mode is different between vports");
1201                 }
1202         }
1203         return err;
1204 }
1205
1206 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
1207 {
1208         kfree(esw->offloads.vport_reps);
1209 }
1210
1211 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
1212 {
1213         int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
1214         struct mlx5_core_dev *dev = esw->dev;
1215         struct mlx5_esw_offload *offloads;
1216         struct mlx5_eswitch_rep *rep;
1217         u8 hw_id[ETH_ALEN];
1218         int vport;
1219
1220         esw->offloads.vport_reps = kcalloc(total_vfs,
1221                                            sizeof(struct mlx5_eswitch_rep),
1222                                            GFP_KERNEL);
1223         if (!esw->offloads.vport_reps)
1224                 return -ENOMEM;
1225
1226         offloads = &esw->offloads;
1227         mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
1228
1229         for (vport = 0; vport < total_vfs; vport++) {
1230                 rep = &offloads->vport_reps[vport];
1231
1232                 rep->vport = vport;
1233                 ether_addr_copy(rep->hw_id, hw_id);
1234         }
1235
1236         offloads->vport_reps[0].vport = MLX5_VPORT_UPLINK;
1237
1238         return 0;
1239 }
1240
1241 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
1242                                           u8 rep_type)
1243 {
1244         struct mlx5_eswitch_rep *rep;
1245         int vport;
1246
1247         for (vport = nvports - 1; vport >= 0; vport--) {
1248                 rep = &esw->offloads.vport_reps[vport];
1249                 if (!rep->rep_if[rep_type].valid)
1250                         continue;
1251
1252                 rep->rep_if[rep_type].unload(rep);
1253         }
1254 }
1255
1256 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
1257 {
1258         u8 rep_type = NUM_REP_TYPES;
1259
1260         while (rep_type-- > 0)
1261                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
1262 }
1263
1264 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
1265                                        u8 rep_type)
1266 {
1267         struct mlx5_eswitch_rep *rep;
1268         int vport;
1269         int err;
1270
1271         for (vport = 0; vport < nvports; vport++) {
1272                 rep = &esw->offloads.vport_reps[vport];
1273                 if (!rep->rep_if[rep_type].valid)
1274                         continue;
1275
1276                 err = rep->rep_if[rep_type].load(esw->dev, rep);
1277                 if (err)
1278                         goto err_reps;
1279         }
1280
1281         return 0;
1282
1283 err_reps:
1284         esw_offloads_unload_reps_type(esw, vport, rep_type);
1285         return err;
1286 }
1287
1288 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
1289 {
1290         u8 rep_type = 0;
1291         int err;
1292
1293         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
1294                 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
1295                 if (err)
1296                         goto err_reps;
1297         }
1298
1299         return err;
1300
1301 err_reps:
1302         while (rep_type-- > 0)
1303                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
1304         return err;
1305 }
1306
1307 #define ESW_OFFLOADS_DEVCOM_PAIR        (0)
1308 #define ESW_OFFLOADS_DEVCOM_UNPAIR      (1)
1309
1310 static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw,
1311                                   struct mlx5_eswitch *peer_esw)
1312 {
1313         int err;
1314
1315         err = esw_add_fdb_peer_miss_rules(esw, peer_esw->dev);
1316         if (err)
1317                 return err;
1318
1319         return 0;
1320 }
1321
1322 void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw);
1323
1324 static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw)
1325 {
1326         mlx5e_tc_clean_fdb_peer_flows(esw);
1327         esw_del_fdb_peer_miss_rules(esw);
1328 }
1329
1330 static int mlx5_esw_offloads_devcom_event(int event,
1331                                           void *my_data,
1332                                           void *event_data)
1333 {
1334         struct mlx5_eswitch *esw = my_data;
1335         struct mlx5_eswitch *peer_esw = event_data;
1336         struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1337         int err;
1338
1339         switch (event) {
1340         case ESW_OFFLOADS_DEVCOM_PAIR:
1341                 err = mlx5_esw_offloads_pair(esw, peer_esw);
1342                 if (err)
1343                         goto err_out;
1344
1345                 err = mlx5_esw_offloads_pair(peer_esw, esw);
1346                 if (err)
1347                         goto err_pair;
1348
1349                 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true);
1350                 break;
1351
1352         case ESW_OFFLOADS_DEVCOM_UNPAIR:
1353                 if (!mlx5_devcom_is_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS))
1354                         break;
1355
1356                 mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false);
1357                 mlx5_esw_offloads_unpair(peer_esw);
1358                 mlx5_esw_offloads_unpair(esw);
1359                 break;
1360         }
1361
1362         return 0;
1363
1364 err_pair:
1365         mlx5_esw_offloads_unpair(esw);
1366
1367 err_out:
1368         mlx5_core_err(esw->dev, "esw offloads devcom event failure, event %u err %d",
1369                       event, err);
1370         return err;
1371 }
1372
1373 static void esw_offloads_devcom_init(struct mlx5_eswitch *esw)
1374 {
1375         struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1376
1377         INIT_LIST_HEAD(&esw->offloads.peer_flows);
1378         mutex_init(&esw->offloads.peer_mutex);
1379
1380         if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
1381                 return;
1382
1383         mlx5_devcom_register_component(devcom,
1384                                        MLX5_DEVCOM_ESW_OFFLOADS,
1385                                        mlx5_esw_offloads_devcom_event,
1386                                        esw);
1387
1388         mlx5_devcom_send_event(devcom,
1389                                MLX5_DEVCOM_ESW_OFFLOADS,
1390                                ESW_OFFLOADS_DEVCOM_PAIR, esw);
1391 }
1392
1393 static void esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw)
1394 {
1395         struct mlx5_devcom *devcom = esw->dev->priv.devcom;
1396
1397         if (!MLX5_CAP_ESW(esw->dev, merged_eswitch))
1398                 return;
1399
1400         mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS,
1401                                ESW_OFFLOADS_DEVCOM_UNPAIR, esw);
1402
1403         mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS);
1404 }
1405
1406 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
1407 {
1408         int err;
1409
1410         mutex_init(&esw->fdb_table.offloads.fdb_prio_lock);
1411
1412         err = esw_create_offloads_fdb_tables(esw, nvports);
1413         if (err)
1414                 return err;
1415
1416         err = esw_create_offloads_table(esw, nvports);
1417         if (err)
1418                 goto create_ft_err;
1419
1420         err = esw_create_vport_rx_group(esw, nvports);
1421         if (err)
1422                 goto create_fg_err;
1423
1424         err = esw_offloads_load_reps(esw, nvports);
1425         if (err)
1426                 goto err_reps;
1427
1428         esw_offloads_devcom_init(esw);
1429         return 0;
1430
1431 err_reps:
1432         esw_destroy_vport_rx_group(esw);
1433
1434 create_fg_err:
1435         esw_destroy_offloads_table(esw);
1436
1437 create_ft_err:
1438         esw_destroy_offloads_fdb_tables(esw);
1439
1440         return err;
1441 }
1442
1443 static int esw_offloads_stop(struct mlx5_eswitch *esw,
1444                              struct netlink_ext_ack *extack)
1445 {
1446         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
1447
1448         mlx5_eswitch_disable_sriov(esw);
1449         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
1450         if (err) {
1451                 NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
1452                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
1453                 if (err1) {
1454                         NL_SET_ERR_MSG_MOD(extack,
1455                                            "Failed setting eswitch back to offloads");
1456                 }
1457         }
1458
1459         return err;
1460 }
1461
1462 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
1463 {
1464         esw_offloads_devcom_cleanup(esw);
1465         esw_offloads_unload_reps(esw, nvports);
1466         esw_destroy_vport_rx_group(esw);
1467         esw_destroy_offloads_table(esw);
1468         esw_destroy_offloads_fdb_tables(esw);
1469 }
1470
1471 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
1472 {
1473         switch (mode) {
1474         case DEVLINK_ESWITCH_MODE_LEGACY:
1475                 *mlx5_mode = SRIOV_LEGACY;
1476                 break;
1477         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
1478                 *mlx5_mode = SRIOV_OFFLOADS;
1479                 break;
1480         default:
1481                 return -EINVAL;
1482         }
1483
1484         return 0;
1485 }
1486
1487 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
1488 {
1489         switch (mlx5_mode) {
1490         case SRIOV_LEGACY:
1491                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
1492                 break;
1493         case SRIOV_OFFLOADS:
1494                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1495                 break;
1496         default:
1497                 return -EINVAL;
1498         }
1499
1500         return 0;
1501 }
1502
1503 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
1504 {
1505         switch (mode) {
1506         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1507                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
1508                 break;
1509         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1510                 *mlx5_mode = MLX5_INLINE_MODE_L2;
1511                 break;
1512         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1513                 *mlx5_mode = MLX5_INLINE_MODE_IP;
1514                 break;
1515         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1516                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
1517                 break;
1518         default:
1519                 return -EINVAL;
1520         }
1521
1522         return 0;
1523 }
1524
1525 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
1526 {
1527         switch (mlx5_mode) {
1528         case MLX5_INLINE_MODE_NONE:
1529                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1530                 break;
1531         case MLX5_INLINE_MODE_L2:
1532                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1533                 break;
1534         case MLX5_INLINE_MODE_IP:
1535                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1536                 break;
1537         case MLX5_INLINE_MODE_TCP_UDP:
1538                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1539                 break;
1540         default:
1541                 return -EINVAL;
1542         }
1543
1544         return 0;
1545 }
1546
1547 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
1548 {
1549         struct mlx5_core_dev *dev = devlink_priv(devlink);
1550
1551         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
1552                 return -EOPNOTSUPP;
1553
1554         if(!MLX5_ESWITCH_MANAGER(dev))
1555                 return -EPERM;
1556
1557         if (dev->priv.eswitch->mode == SRIOV_NONE)
1558                 return -EOPNOTSUPP;
1559
1560         return 0;
1561 }
1562
1563 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
1564                                   struct netlink_ext_ack *extack)
1565 {
1566         struct mlx5_core_dev *dev = devlink_priv(devlink);
1567         u16 cur_mlx5_mode, mlx5_mode = 0;
1568         int err;
1569
1570         err = mlx5_devlink_eswitch_check(devlink);
1571         if (err)
1572                 return err;
1573
1574         cur_mlx5_mode = dev->priv.eswitch->mode;
1575
1576         if (esw_mode_from_devlink(mode, &mlx5_mode))
1577                 return -EINVAL;
1578
1579         if (cur_mlx5_mode == mlx5_mode)
1580                 return 0;
1581
1582         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1583                 return esw_offloads_start(dev->priv.eswitch, extack);
1584         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1585                 return esw_offloads_stop(dev->priv.eswitch, extack);
1586         else
1587                 return -EINVAL;
1588 }
1589
1590 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1591 {
1592         struct mlx5_core_dev *dev = devlink_priv(devlink);
1593         int err;
1594
1595         err = mlx5_devlink_eswitch_check(devlink);
1596         if (err)
1597                 return err;
1598
1599         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1600 }
1601
1602 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
1603                                          struct netlink_ext_ack *extack)
1604 {
1605         struct mlx5_core_dev *dev = devlink_priv(devlink);
1606         struct mlx5_eswitch *esw = dev->priv.eswitch;
1607         int err, vport;
1608         u8 mlx5_mode;
1609
1610         err = mlx5_devlink_eswitch_check(devlink);
1611         if (err)
1612                 return err;
1613
1614         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1615         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1616                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1617                         return 0;
1618                 /* fall through */
1619         case MLX5_CAP_INLINE_MODE_L2:
1620                 NL_SET_ERR_MSG_MOD(extack, "Inline mode can't be set");
1621                 return -EOPNOTSUPP;
1622         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1623                 break;
1624         }
1625
1626         if (esw->offloads.num_flows > 0) {
1627                 NL_SET_ERR_MSG_MOD(extack,
1628                                    "Can't set inline mode when flows are configured");
1629                 return -EOPNOTSUPP;
1630         }
1631
1632         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1633         if (err)
1634                 goto out;
1635
1636         for (vport = 1; vport < esw->enabled_vports; vport++) {
1637                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1638                 if (err) {
1639                         NL_SET_ERR_MSG_MOD(extack,
1640                                            "Failed to set min inline on vport");
1641                         goto revert_inline_mode;
1642                 }
1643         }
1644
1645         esw->offloads.inline_mode = mlx5_mode;
1646         return 0;
1647
1648 revert_inline_mode:
1649         while (--vport > 0)
1650                 mlx5_modify_nic_vport_min_inline(dev,
1651                                                  vport,
1652                                                  esw->offloads.inline_mode);
1653 out:
1654         return err;
1655 }
1656
1657 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1658 {
1659         struct mlx5_core_dev *dev = devlink_priv(devlink);
1660         struct mlx5_eswitch *esw = dev->priv.eswitch;
1661         int err;
1662
1663         err = mlx5_devlink_eswitch_check(devlink);
1664         if (err)
1665                 return err;
1666
1667         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1668 }
1669
1670 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1671 {
1672         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1673         struct mlx5_core_dev *dev = esw->dev;
1674         int vport;
1675
1676         if (!MLX5_CAP_GEN(dev, vport_group_manager))
1677                 return -EOPNOTSUPP;
1678
1679         if (esw->mode == SRIOV_NONE)
1680                 return -EOPNOTSUPP;
1681
1682         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1683         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1684                 mlx5_mode = MLX5_INLINE_MODE_NONE;
1685                 goto out;
1686         case MLX5_CAP_INLINE_MODE_L2:
1687                 mlx5_mode = MLX5_INLINE_MODE_L2;
1688                 goto out;
1689         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1690                 goto query_vports;
1691         }
1692
1693 query_vports:
1694         for (vport = 1; vport <= nvfs; vport++) {
1695                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1696                 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1697                         return -EINVAL;
1698                 prev_mlx5_mode = mlx5_mode;
1699         }
1700
1701 out:
1702         *mode = mlx5_mode;
1703         return 0;
1704 }
1705
1706 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap,
1707                                         struct netlink_ext_ack *extack)
1708 {
1709         struct mlx5_core_dev *dev = devlink_priv(devlink);
1710         struct mlx5_eswitch *esw = dev->priv.eswitch;
1711         int err;
1712
1713         err = mlx5_devlink_eswitch_check(devlink);
1714         if (err)
1715                 return err;
1716
1717         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1718             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
1719              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1720                 return -EOPNOTSUPP;
1721
1722         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1723                 return -EOPNOTSUPP;
1724
1725         if (esw->mode == SRIOV_LEGACY) {
1726                 esw->offloads.encap = encap;
1727                 return 0;
1728         }
1729
1730         if (esw->offloads.encap == encap)
1731                 return 0;
1732
1733         if (esw->offloads.num_flows > 0) {
1734                 NL_SET_ERR_MSG_MOD(extack,
1735                                    "Can't set encapsulation when flows are configured");
1736                 return -EOPNOTSUPP;
1737         }
1738
1739         esw_destroy_offloads_fdb_tables(esw);
1740
1741         esw->offloads.encap = encap;
1742
1743         err = esw_create_offloads_fdb_tables(esw, esw->nvports);
1744
1745         if (err) {
1746                 NL_SET_ERR_MSG_MOD(extack,
1747                                    "Failed re-creating fast FDB table");
1748                 esw->offloads.encap = !encap;
1749                 (void)esw_create_offloads_fdb_tables(esw, esw->nvports);
1750         }
1751
1752         return err;
1753 }
1754
1755 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1756 {
1757         struct mlx5_core_dev *dev = devlink_priv(devlink);
1758         struct mlx5_eswitch *esw = dev->priv.eswitch;
1759         int err;
1760
1761         err = mlx5_devlink_eswitch_check(devlink);
1762         if (err)
1763                 return err;
1764
1765         *encap = esw->offloads.encap;
1766         return 0;
1767 }
1768
1769 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1770                                      int vport_index,
1771                                      struct mlx5_eswitch_rep_if *__rep_if,
1772                                      u8 rep_type)
1773 {
1774         struct mlx5_esw_offload *offloads = &esw->offloads;
1775         struct mlx5_eswitch_rep_if *rep_if;
1776
1777         rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1778
1779         rep_if->load   = __rep_if->load;
1780         rep_if->unload = __rep_if->unload;
1781         rep_if->get_proto_dev = __rep_if->get_proto_dev;
1782         rep_if->priv = __rep_if->priv;
1783
1784         rep_if->valid = true;
1785 }
1786 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1787
1788 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1789                                        int vport_index, u8 rep_type)
1790 {
1791         struct mlx5_esw_offload *offloads = &esw->offloads;
1792         struct mlx5_eswitch_rep *rep;
1793
1794         rep = &offloads->vport_reps[vport_index];
1795
1796         if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1797                 rep->rep_if[rep_type].unload(rep);
1798
1799         rep->rep_if[rep_type].valid = false;
1800 }
1801 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1802
1803 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1804 {
1805 #define UPLINK_REP_INDEX 0
1806         struct mlx5_esw_offload *offloads = &esw->offloads;
1807         struct mlx5_eswitch_rep *rep;
1808
1809         rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1810         return rep->rep_if[rep_type].priv;
1811 }
1812
1813 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1814                                  int vport,
1815                                  u8 rep_type)
1816 {
1817         struct mlx5_esw_offload *offloads = &esw->offloads;
1818         struct mlx5_eswitch_rep *rep;
1819
1820         if (vport == MLX5_VPORT_UPLINK)
1821                 vport = UPLINK_REP_INDEX;
1822
1823         rep = &offloads->vport_reps[vport];
1824
1825         if (rep->rep_if[rep_type].valid &&
1826             rep->rep_if[rep_type].get_proto_dev)
1827                 return rep->rep_if[rep_type].get_proto_dev(rep);
1828         return NULL;
1829 }
1830 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1831
1832 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1833 {
1834         return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1835 }
1836 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1837
1838 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1839                                                 int vport)
1840 {
1841         return &esw->offloads.vport_reps[vport];
1842 }
1843 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);