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