]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
net/mlx5e: Support offloaded TC flows with no matches on headers
[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
41 enum {
42         FDB_FAST_PATH = 0,
43         FDB_SLOW_PATH
44 };
45
46 struct mlx5_flow_handle *
47 mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
48                                 struct mlx5_flow_spec *spec,
49                                 struct mlx5_esw_flow_attr *attr)
50 {
51         struct mlx5_flow_destination dest[2] = {};
52         struct mlx5_flow_act flow_act = {0};
53         struct mlx5_fc *counter = NULL;
54         struct mlx5_flow_handle *rule;
55         void *misc;
56         int i = 0;
57
58         if (esw->mode != SRIOV_OFFLOADS)
59                 return ERR_PTR(-EOPNOTSUPP);
60
61         flow_act.action = attr->action;
62         /* if per flow vlan pop/push is emulated, don't set that into the firmware */
63         if (!mlx5_eswitch_vlan_actions_supported(esw->dev))
64                 flow_act.action &= ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH |
65                                      MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
66         else if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) {
67                 flow_act.vlan.ethtype = ntohs(attr->vlan_proto);
68                 flow_act.vlan.vid = attr->vlan_vid;
69                 flow_act.vlan.prio = attr->vlan_prio;
70         }
71
72         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
73                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
74                 dest[i].vport_num = attr->out_rep->vport;
75                 i++;
76         }
77         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
78                 counter = mlx5_fc_create(esw->dev, true);
79                 if (IS_ERR(counter)) {
80                         rule = ERR_CAST(counter);
81                         goto err_counter_alloc;
82                 }
83                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
84                 dest[i].counter = counter;
85                 i++;
86         }
87
88         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
89         MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
90
91         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
92         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
93
94         if (attr->match_level == MLX5_MATCH_NONE)
95                 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
96         else
97                 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
98                                               MLX5_MATCH_MISC_PARAMETERS;
99
100         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
101                 spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
102
103         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
104                 flow_act.modify_id = attr->mod_hdr_id;
105
106         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
107                 flow_act.encap_id = attr->encap_id;
108
109         rule = mlx5_add_flow_rules((struct mlx5_flow_table *)esw->fdb_table.fdb,
110                                    spec, &flow_act, dest, i);
111         if (IS_ERR(rule))
112                 goto err_add_rule;
113         else
114                 esw->offloads.num_flows++;
115
116         return rule;
117
118 err_add_rule:
119         mlx5_fc_destroy(esw->dev, counter);
120 err_counter_alloc:
121         return rule;
122 }
123
124 void
125 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
126                                 struct mlx5_flow_handle *rule,
127                                 struct mlx5_esw_flow_attr *attr)
128 {
129         struct mlx5_fc *counter = NULL;
130
131         counter = mlx5_flow_rule_counter(rule);
132         mlx5_del_flow_rules(rule);
133         mlx5_fc_destroy(esw->dev, counter);
134         esw->offloads.num_flows--;
135 }
136
137 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
138 {
139         struct mlx5_eswitch_rep *rep;
140         int vf_vport, err = 0;
141
142         esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
143         for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
144                 rep = &esw->offloads.vport_reps[vf_vport];
145                 if (!rep->rep_if[REP_ETH].valid)
146                         continue;
147
148                 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
149                 if (err)
150                         goto out;
151         }
152
153 out:
154         return err;
155 }
156
157 static struct mlx5_eswitch_rep *
158 esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
159 {
160         struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
161
162         in_rep  = attr->in_rep;
163         out_rep = attr->out_rep;
164
165         if (push)
166                 vport = in_rep;
167         else if (pop)
168                 vport = out_rep;
169         else
170                 vport = in_rep;
171
172         return vport;
173 }
174
175 static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
176                                      bool push, bool pop, bool fwd)
177 {
178         struct mlx5_eswitch_rep *in_rep, *out_rep;
179
180         if ((push || pop) && !fwd)
181                 goto out_notsupp;
182
183         in_rep  = attr->in_rep;
184         out_rep = attr->out_rep;
185
186         if (push && in_rep->vport == FDB_UPLINK_VPORT)
187                 goto out_notsupp;
188
189         if (pop && out_rep->vport == FDB_UPLINK_VPORT)
190                 goto out_notsupp;
191
192         /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
193         if (!push && !pop && fwd)
194                 if (in_rep->vlan && out_rep->vport == FDB_UPLINK_VPORT)
195                         goto out_notsupp;
196
197         /* protects against (1) setting rules with different vlans to push and
198          * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
199          */
200         if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan_vid))
201                 goto out_notsupp;
202
203         return 0;
204
205 out_notsupp:
206         return -EOPNOTSUPP;
207 }
208
209 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
210                                  struct mlx5_esw_flow_attr *attr)
211 {
212         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
213         struct mlx5_eswitch_rep *vport = NULL;
214         bool push, pop, fwd;
215         int err = 0;
216
217         /* nop if we're on the vlan push/pop non emulation mode */
218         if (mlx5_eswitch_vlan_actions_supported(esw->dev))
219                 return 0;
220
221         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
222         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
223         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
224
225         err = esw_add_vlan_action_check(attr, push, pop, fwd);
226         if (err)
227                 return err;
228
229         attr->vlan_handled = false;
230
231         vport = esw_vlan_action_get_vport(attr, push, pop);
232
233         if (!push && !pop && fwd) {
234                 /* tracks VF --> wire rules without vlan push action */
235                 if (attr->out_rep->vport == FDB_UPLINK_VPORT) {
236                         vport->vlan_refcount++;
237                         attr->vlan_handled = true;
238                 }
239
240                 return 0;
241         }
242
243         if (!push && !pop)
244                 return 0;
245
246         if (!(offloads->vlan_push_pop_refcount)) {
247                 /* it's the 1st vlan rule, apply global vlan pop policy */
248                 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
249                 if (err)
250                         goto out;
251         }
252         offloads->vlan_push_pop_refcount++;
253
254         if (push) {
255                 if (vport->vlan_refcount)
256                         goto skip_set_push;
257
258                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan_vid, 0,
259                                                     SET_VLAN_INSERT | SET_VLAN_STRIP);
260                 if (err)
261                         goto out;
262                 vport->vlan = attr->vlan_vid;
263 skip_set_push:
264                 vport->vlan_refcount++;
265         }
266 out:
267         if (!err)
268                 attr->vlan_handled = true;
269         return err;
270 }
271
272 int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
273                                  struct mlx5_esw_flow_attr *attr)
274 {
275         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
276         struct mlx5_eswitch_rep *vport = NULL;
277         bool push, pop, fwd;
278         int err = 0;
279
280         /* nop if we're on the vlan push/pop non emulation mode */
281         if (mlx5_eswitch_vlan_actions_supported(esw->dev))
282                 return 0;
283
284         if (!attr->vlan_handled)
285                 return 0;
286
287         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
288         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
289         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
290
291         vport = esw_vlan_action_get_vport(attr, push, pop);
292
293         if (!push && !pop && fwd) {
294                 /* tracks VF --> wire rules without vlan push action */
295                 if (attr->out_rep->vport == FDB_UPLINK_VPORT)
296                         vport->vlan_refcount--;
297
298                 return 0;
299         }
300
301         if (push) {
302                 vport->vlan_refcount--;
303                 if (vport->vlan_refcount)
304                         goto skip_unset_push;
305
306                 vport->vlan = 0;
307                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
308                                                     0, 0, SET_VLAN_STRIP);
309                 if (err)
310                         goto out;
311         }
312
313 skip_unset_push:
314         offloads->vlan_push_pop_refcount--;
315         if (offloads->vlan_push_pop_refcount)
316                 return 0;
317
318         /* no more vlan rules, stop global vlan pop policy */
319         err = esw_set_global_vlan_pop(esw, 0);
320
321 out:
322         return err;
323 }
324
325 struct mlx5_flow_handle *
326 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn)
327 {
328         struct mlx5_flow_act flow_act = {0};
329         struct mlx5_flow_destination dest = {};
330         struct mlx5_flow_handle *flow_rule;
331         struct mlx5_flow_spec *spec;
332         void *misc;
333
334         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
335         if (!spec) {
336                 flow_rule = ERR_PTR(-ENOMEM);
337                 goto out;
338         }
339
340         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
341         MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
342         MLX5_SET(fte_match_set_misc, misc, source_port, 0x0); /* source vport is 0 */
343
344         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
345         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
346         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
347
348         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
349         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
350         dest.vport_num = vport;
351         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
352
353         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fdb, spec,
354                                         &flow_act, &dest, 1);
355         if (IS_ERR(flow_rule))
356                 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
357 out:
358         kvfree(spec);
359         return flow_rule;
360 }
361 EXPORT_SYMBOL(mlx5_eswitch_add_send_to_vport_rule);
362
363 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
364 {
365         mlx5_del_flow_rules(rule);
366 }
367
368 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
369 {
370         struct mlx5_flow_act flow_act = {0};
371         struct mlx5_flow_destination dest = {};
372         struct mlx5_flow_handle *flow_rule = NULL;
373         struct mlx5_flow_spec *spec;
374         void *headers_c;
375         void *headers_v;
376         int err = 0;
377         u8 *dmac_c;
378         u8 *dmac_v;
379
380         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
381         if (!spec) {
382                 err = -ENOMEM;
383                 goto out;
384         }
385
386         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
387         headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
388                                  outer_headers);
389         dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c,
390                               outer_headers.dmac_47_16);
391         dmac_c[0] = 0x01;
392
393         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
394         dest.vport_num = 0;
395         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
396
397         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fdb, spec,
398                                         &flow_act, &dest, 1);
399         if (IS_ERR(flow_rule)) {
400                 err = PTR_ERR(flow_rule);
401                 esw_warn(esw->dev,  "FDB: Failed to add unicast miss flow rule err %d\n", err);
402                 goto out;
403         }
404
405         esw->fdb_table.offloads.miss_rule_uni = flow_rule;
406
407         headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
408                                  outer_headers);
409         dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v,
410                               outer_headers.dmac_47_16);
411         dmac_v[0] = 0x01;
412         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fdb, spec,
413                                         &flow_act, &dest, 1);
414         if (IS_ERR(flow_rule)) {
415                 err = PTR_ERR(flow_rule);
416                 esw_warn(esw->dev, "FDB: Failed to add multicast miss flow rule err %d\n", err);
417                 mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
418                 goto out;
419         }
420
421         esw->fdb_table.offloads.miss_rule_multi = flow_rule;
422
423 out:
424         kvfree(spec);
425         return err;
426 }
427
428 #define ESW_OFFLOADS_NUM_GROUPS  4
429
430 static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
431 {
432         struct mlx5_core_dev *dev = esw->dev;
433         struct mlx5_flow_namespace *root_ns;
434         struct mlx5_flow_table *fdb = NULL;
435         int esw_size, err = 0;
436         u32 flags = 0;
437         u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
438                                 MLX5_CAP_GEN(dev, max_flow_counter_15_0);
439
440         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
441         if (!root_ns) {
442                 esw_warn(dev, "Failed to get FDB flow namespace\n");
443                 err = -EOPNOTSUPP;
444                 goto out;
445         }
446
447         esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
448                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
449                   max_flow_counter, ESW_OFFLOADS_NUM_GROUPS);
450
451         esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS,
452                          1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
453
454         if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
455                 flags |= MLX5_FLOW_TABLE_TUNNEL_EN;
456
457         fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
458                                                   esw_size,
459                                                   ESW_OFFLOADS_NUM_GROUPS, 0,
460                                                   flags);
461         if (IS_ERR(fdb)) {
462                 err = PTR_ERR(fdb);
463                 esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
464                 goto out;
465         }
466         esw->fdb_table.fdb = fdb;
467
468 out:
469         return err;
470 }
471
472 static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
473 {
474         mlx5_destroy_flow_table(esw->fdb_table.fdb);
475 }
476
477 #define MAX_PF_SQ 256
478 #define MAX_SQ_NVPORTS 32
479
480 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
481 {
482         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
483         struct mlx5_flow_table_attr ft_attr = {};
484         struct mlx5_core_dev *dev = esw->dev;
485         struct mlx5_flow_namespace *root_ns;
486         struct mlx5_flow_table *fdb = NULL;
487         int table_size, ix, err = 0;
488         struct mlx5_flow_group *g;
489         void *match_criteria;
490         u32 *flow_group_in;
491         u8 *dmac;
492
493         esw_debug(esw->dev, "Create offloads FDB Tables\n");
494         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
495         if (!flow_group_in)
496                 return -ENOMEM;
497
498         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
499         if (!root_ns) {
500                 esw_warn(dev, "Failed to get FDB flow namespace\n");
501                 err = -EOPNOTSUPP;
502                 goto ns_err;
503         }
504
505         err = esw_create_offloads_fast_fdb_table(esw);
506         if (err)
507                 goto fast_fdb_err;
508
509         table_size = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ + 2;
510
511         ft_attr.max_fte = table_size;
512         ft_attr.prio = FDB_SLOW_PATH;
513
514         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
515         if (IS_ERR(fdb)) {
516                 err = PTR_ERR(fdb);
517                 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
518                 goto slow_fdb_err;
519         }
520         esw->fdb_table.offloads.fdb = fdb;
521
522         /* create send-to-vport group */
523         memset(flow_group_in, 0, inlen);
524         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
525                  MLX5_MATCH_MISC_PARAMETERS);
526
527         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
528
529         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
530         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
531
532         ix = nvports * MAX_SQ_NVPORTS + MAX_PF_SQ;
533         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
534         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
535
536         g = mlx5_create_flow_group(fdb, flow_group_in);
537         if (IS_ERR(g)) {
538                 err = PTR_ERR(g);
539                 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
540                 goto send_vport_err;
541         }
542         esw->fdb_table.offloads.send_to_vport_grp = g;
543
544         /* create miss group */
545         memset(flow_group_in, 0, inlen);
546         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
547                  MLX5_MATCH_OUTER_HEADERS);
548         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
549                                       match_criteria);
550         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
551                             outer_headers.dmac_47_16);
552         dmac[0] = 0x01;
553
554         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
555         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix + 2);
556
557         g = mlx5_create_flow_group(fdb, flow_group_in);
558         if (IS_ERR(g)) {
559                 err = PTR_ERR(g);
560                 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
561                 goto miss_err;
562         }
563         esw->fdb_table.offloads.miss_grp = g;
564
565         err = esw_add_fdb_miss_rule(esw);
566         if (err)
567                 goto miss_rule_err;
568
569         return 0;
570
571 miss_rule_err:
572         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
573 miss_err:
574         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
575 send_vport_err:
576         mlx5_destroy_flow_table(esw->fdb_table.offloads.fdb);
577 slow_fdb_err:
578         mlx5_destroy_flow_table(esw->fdb_table.fdb);
579 fast_fdb_err:
580 ns_err:
581         kvfree(flow_group_in);
582         return err;
583 }
584
585 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
586 {
587         if (!esw->fdb_table.fdb)
588                 return;
589
590         esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
591         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_multi);
592         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule_uni);
593         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
594         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
595
596         mlx5_destroy_flow_table(esw->fdb_table.offloads.fdb);
597         esw_destroy_offloads_fast_fdb_table(esw);
598 }
599
600 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
601 {
602         struct mlx5_flow_table_attr ft_attr = {};
603         struct mlx5_core_dev *dev = esw->dev;
604         struct mlx5_flow_table *ft_offloads;
605         struct mlx5_flow_namespace *ns;
606         int err = 0;
607
608         ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
609         if (!ns) {
610                 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
611                 return -EOPNOTSUPP;
612         }
613
614         ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
615
616         ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
617         if (IS_ERR(ft_offloads)) {
618                 err = PTR_ERR(ft_offloads);
619                 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
620                 return err;
621         }
622
623         esw->offloads.ft_offloads = ft_offloads;
624         return 0;
625 }
626
627 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
628 {
629         struct mlx5_esw_offload *offloads = &esw->offloads;
630
631         mlx5_destroy_flow_table(offloads->ft_offloads);
632 }
633
634 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
635 {
636         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
637         struct mlx5_flow_group *g;
638         struct mlx5_priv *priv = &esw->dev->priv;
639         u32 *flow_group_in;
640         void *match_criteria, *misc;
641         int err = 0;
642         int nvports = priv->sriov.num_vfs + 2;
643
644         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
645         if (!flow_group_in)
646                 return -ENOMEM;
647
648         /* create vport rx group */
649         memset(flow_group_in, 0, inlen);
650         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
651                  MLX5_MATCH_MISC_PARAMETERS);
652
653         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
654         misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
655         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
656
657         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
658         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
659
660         g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
661
662         if (IS_ERR(g)) {
663                 err = PTR_ERR(g);
664                 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
665                 goto out;
666         }
667
668         esw->offloads.vport_rx_group = g;
669 out:
670         kfree(flow_group_in);
671         return err;
672 }
673
674 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
675 {
676         mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
677 }
678
679 struct mlx5_flow_handle *
680 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn)
681 {
682         struct mlx5_flow_act flow_act = {0};
683         struct mlx5_flow_destination dest = {};
684         struct mlx5_flow_handle *flow_rule;
685         struct mlx5_flow_spec *spec;
686         void *misc;
687
688         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
689         if (!spec) {
690                 flow_rule = ERR_PTR(-ENOMEM);
691                 goto out;
692         }
693
694         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
695         MLX5_SET(fte_match_set_misc, misc, source_port, vport);
696
697         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
698         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
699
700         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
701         dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
702         dest.tir_num = tirn;
703
704         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
705         flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
706                                         &flow_act, &dest, 1);
707         if (IS_ERR(flow_rule)) {
708                 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
709                 goto out;
710         }
711
712 out:
713         kvfree(spec);
714         return flow_rule;
715 }
716
717 static int esw_offloads_start(struct mlx5_eswitch *esw)
718 {
719         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
720
721         if (esw->mode != SRIOV_LEGACY) {
722                 esw_warn(esw->dev, "Can't set offloads mode, SRIOV legacy not enabled\n");
723                 return -EINVAL;
724         }
725
726         mlx5_eswitch_disable_sriov(esw);
727         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
728         if (err) {
729                 esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
730                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
731                 if (err1)
732                         esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
733         }
734         if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
735                 if (mlx5_eswitch_inline_mode_get(esw,
736                                                  num_vfs,
737                                                  &esw->offloads.inline_mode)) {
738                         esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
739                         esw_warn(esw->dev, "Inline mode is different between vports\n");
740                 }
741         }
742         return err;
743 }
744
745 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
746 {
747         kfree(esw->offloads.vport_reps);
748 }
749
750 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
751 {
752         int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
753         struct mlx5_core_dev *dev = esw->dev;
754         struct mlx5_esw_offload *offloads;
755         struct mlx5_eswitch_rep *rep;
756         u8 hw_id[ETH_ALEN];
757         int vport;
758
759         esw->offloads.vport_reps = kcalloc(total_vfs,
760                                            sizeof(struct mlx5_eswitch_rep),
761                                            GFP_KERNEL);
762         if (!esw->offloads.vport_reps)
763                 return -ENOMEM;
764
765         offloads = &esw->offloads;
766         mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
767
768         for (vport = 0; vport < total_vfs; vport++) {
769                 rep = &offloads->vport_reps[vport];
770
771                 rep->vport = vport;
772                 ether_addr_copy(rep->hw_id, hw_id);
773         }
774
775         offloads->vport_reps[0].vport = FDB_UPLINK_VPORT;
776
777         return 0;
778 }
779
780 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
781                                           u8 rep_type)
782 {
783         struct mlx5_eswitch_rep *rep;
784         int vport;
785
786         for (vport = nvports - 1; vport >= 0; vport--) {
787                 rep = &esw->offloads.vport_reps[vport];
788                 if (!rep->rep_if[rep_type].valid)
789                         continue;
790
791                 rep->rep_if[rep_type].unload(rep);
792         }
793 }
794
795 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
796 {
797         u8 rep_type = NUM_REP_TYPES;
798
799         while (rep_type-- > 0)
800                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
801 }
802
803 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
804                                        u8 rep_type)
805 {
806         struct mlx5_eswitch_rep *rep;
807         int vport;
808         int err;
809
810         for (vport = 0; vport < nvports; vport++) {
811                 rep = &esw->offloads.vport_reps[vport];
812                 if (!rep->rep_if[rep_type].valid)
813                         continue;
814
815                 err = rep->rep_if[rep_type].load(esw->dev, rep);
816                 if (err)
817                         goto err_reps;
818         }
819
820         return 0;
821
822 err_reps:
823         esw_offloads_unload_reps_type(esw, vport, rep_type);
824         return err;
825 }
826
827 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
828 {
829         u8 rep_type = 0;
830         int err;
831
832         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
833                 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
834                 if (err)
835                         goto err_reps;
836         }
837
838         return err;
839
840 err_reps:
841         while (rep_type-- > 0)
842                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
843         return err;
844 }
845
846 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
847 {
848         int err;
849
850         err = esw_create_offloads_fdb_tables(esw, nvports);
851         if (err)
852                 return err;
853
854         err = esw_create_offloads_table(esw);
855         if (err)
856                 goto create_ft_err;
857
858         err = esw_create_vport_rx_group(esw);
859         if (err)
860                 goto create_fg_err;
861
862         err = esw_offloads_load_reps(esw, nvports);
863         if (err)
864                 goto err_reps;
865
866         return 0;
867
868 err_reps:
869         esw_destroy_vport_rx_group(esw);
870
871 create_fg_err:
872         esw_destroy_offloads_table(esw);
873
874 create_ft_err:
875         esw_destroy_offloads_fdb_tables(esw);
876
877         return err;
878 }
879
880 static int esw_offloads_stop(struct mlx5_eswitch *esw)
881 {
882         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
883
884         mlx5_eswitch_disable_sriov(esw);
885         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
886         if (err) {
887                 esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err);
888                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
889                 if (err1)
890                         esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
891         }
892
893         /* enable back PF RoCE */
894         mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
895
896         return err;
897 }
898
899 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
900 {
901         esw_offloads_unload_reps(esw, nvports);
902         esw_destroy_vport_rx_group(esw);
903         esw_destroy_offloads_table(esw);
904         esw_destroy_offloads_fdb_tables(esw);
905 }
906
907 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
908 {
909         switch (mode) {
910         case DEVLINK_ESWITCH_MODE_LEGACY:
911                 *mlx5_mode = SRIOV_LEGACY;
912                 break;
913         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
914                 *mlx5_mode = SRIOV_OFFLOADS;
915                 break;
916         default:
917                 return -EINVAL;
918         }
919
920         return 0;
921 }
922
923 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
924 {
925         switch (mlx5_mode) {
926         case SRIOV_LEGACY:
927                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
928                 break;
929         case SRIOV_OFFLOADS:
930                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
931                 break;
932         default:
933                 return -EINVAL;
934         }
935
936         return 0;
937 }
938
939 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
940 {
941         switch (mode) {
942         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
943                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
944                 break;
945         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
946                 *mlx5_mode = MLX5_INLINE_MODE_L2;
947                 break;
948         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
949                 *mlx5_mode = MLX5_INLINE_MODE_IP;
950                 break;
951         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
952                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
953                 break;
954         default:
955                 return -EINVAL;
956         }
957
958         return 0;
959 }
960
961 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
962 {
963         switch (mlx5_mode) {
964         case MLX5_INLINE_MODE_NONE:
965                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
966                 break;
967         case MLX5_INLINE_MODE_L2:
968                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
969                 break;
970         case MLX5_INLINE_MODE_IP:
971                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
972                 break;
973         case MLX5_INLINE_MODE_TCP_UDP:
974                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
975                 break;
976         default:
977                 return -EINVAL;
978         }
979
980         return 0;
981 }
982
983 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
984 {
985         struct mlx5_core_dev *dev = devlink_priv(devlink);
986
987         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
988                 return -EOPNOTSUPP;
989
990         if (!MLX5_CAP_GEN(dev, vport_group_manager))
991                 return -EOPNOTSUPP;
992
993         if (dev->priv.eswitch->mode == SRIOV_NONE)
994                 return -EOPNOTSUPP;
995
996         return 0;
997 }
998
999 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
1000 {
1001         struct mlx5_core_dev *dev = devlink_priv(devlink);
1002         u16 cur_mlx5_mode, mlx5_mode = 0;
1003         int err;
1004
1005         err = mlx5_devlink_eswitch_check(devlink);
1006         if (err)
1007                 return err;
1008
1009         cur_mlx5_mode = dev->priv.eswitch->mode;
1010
1011         if (esw_mode_from_devlink(mode, &mlx5_mode))
1012                 return -EINVAL;
1013
1014         if (cur_mlx5_mode == mlx5_mode)
1015                 return 0;
1016
1017         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
1018                 return esw_offloads_start(dev->priv.eswitch);
1019         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
1020                 return esw_offloads_stop(dev->priv.eswitch);
1021         else
1022                 return -EINVAL;
1023 }
1024
1025 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
1026 {
1027         struct mlx5_core_dev *dev = devlink_priv(devlink);
1028         int err;
1029
1030         err = mlx5_devlink_eswitch_check(devlink);
1031         if (err)
1032                 return err;
1033
1034         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
1035 }
1036
1037 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
1038 {
1039         struct mlx5_core_dev *dev = devlink_priv(devlink);
1040         struct mlx5_eswitch *esw = dev->priv.eswitch;
1041         int err, vport;
1042         u8 mlx5_mode;
1043
1044         err = mlx5_devlink_eswitch_check(devlink);
1045         if (err)
1046                 return err;
1047
1048         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1049         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1050                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1051                         return 0;
1052                 /* fall through */
1053         case MLX5_CAP_INLINE_MODE_L2:
1054                 esw_warn(dev, "Inline mode can't be set\n");
1055                 return -EOPNOTSUPP;
1056         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1057                 break;
1058         }
1059
1060         if (esw->offloads.num_flows > 0) {
1061                 esw_warn(dev, "Can't set inline mode when flows are configured\n");
1062                 return -EOPNOTSUPP;
1063         }
1064
1065         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1066         if (err)
1067                 goto out;
1068
1069         for (vport = 1; vport < esw->enabled_vports; vport++) {
1070                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1071                 if (err) {
1072                         esw_warn(dev, "Failed to set min inline on vport %d\n",
1073                                  vport);
1074                         goto revert_inline_mode;
1075                 }
1076         }
1077
1078         esw->offloads.inline_mode = mlx5_mode;
1079         return 0;
1080
1081 revert_inline_mode:
1082         while (--vport > 0)
1083                 mlx5_modify_nic_vport_min_inline(dev,
1084                                                  vport,
1085                                                  esw->offloads.inline_mode);
1086 out:
1087         return err;
1088 }
1089
1090 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1091 {
1092         struct mlx5_core_dev *dev = devlink_priv(devlink);
1093         struct mlx5_eswitch *esw = dev->priv.eswitch;
1094         int err;
1095
1096         err = mlx5_devlink_eswitch_check(devlink);
1097         if (err)
1098                 return err;
1099
1100         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1101 }
1102
1103 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1104 {
1105         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1106         struct mlx5_core_dev *dev = esw->dev;
1107         int vport;
1108
1109         if (!MLX5_CAP_GEN(dev, vport_group_manager))
1110                 return -EOPNOTSUPP;
1111
1112         if (esw->mode == SRIOV_NONE)
1113                 return -EOPNOTSUPP;
1114
1115         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1116         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1117                 mlx5_mode = MLX5_INLINE_MODE_NONE;
1118                 goto out;
1119         case MLX5_CAP_INLINE_MODE_L2:
1120                 mlx5_mode = MLX5_INLINE_MODE_L2;
1121                 goto out;
1122         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1123                 goto query_vports;
1124         }
1125
1126 query_vports:
1127         for (vport = 1; vport <= nvfs; vport++) {
1128                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1129                 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1130                         return -EINVAL;
1131                 prev_mlx5_mode = mlx5_mode;
1132         }
1133
1134 out:
1135         *mode = mlx5_mode;
1136         return 0;
1137 }
1138
1139 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
1140 {
1141         struct mlx5_core_dev *dev = devlink_priv(devlink);
1142         struct mlx5_eswitch *esw = dev->priv.eswitch;
1143         int err;
1144
1145         err = mlx5_devlink_eswitch_check(devlink);
1146         if (err)
1147                 return err;
1148
1149         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1150             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
1151              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1152                 return -EOPNOTSUPP;
1153
1154         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1155                 return -EOPNOTSUPP;
1156
1157         if (esw->mode == SRIOV_LEGACY) {
1158                 esw->offloads.encap = encap;
1159                 return 0;
1160         }
1161
1162         if (esw->offloads.encap == encap)
1163                 return 0;
1164
1165         if (esw->offloads.num_flows > 0) {
1166                 esw_warn(dev, "Can't set encapsulation when flows are configured\n");
1167                 return -EOPNOTSUPP;
1168         }
1169
1170         esw_destroy_offloads_fast_fdb_table(esw);
1171
1172         esw->offloads.encap = encap;
1173         err = esw_create_offloads_fast_fdb_table(esw);
1174         if (err) {
1175                 esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
1176                 esw->offloads.encap = !encap;
1177                 (void)esw_create_offloads_fast_fdb_table(esw);
1178         }
1179         return err;
1180 }
1181
1182 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1183 {
1184         struct mlx5_core_dev *dev = devlink_priv(devlink);
1185         struct mlx5_eswitch *esw = dev->priv.eswitch;
1186         int err;
1187
1188         err = mlx5_devlink_eswitch_check(devlink);
1189         if (err)
1190                 return err;
1191
1192         *encap = esw->offloads.encap;
1193         return 0;
1194 }
1195
1196 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1197                                      int vport_index,
1198                                      struct mlx5_eswitch_rep_if *__rep_if,
1199                                      u8 rep_type)
1200 {
1201         struct mlx5_esw_offload *offloads = &esw->offloads;
1202         struct mlx5_eswitch_rep_if *rep_if;
1203
1204         rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1205
1206         rep_if->load   = __rep_if->load;
1207         rep_if->unload = __rep_if->unload;
1208         rep_if->get_proto_dev = __rep_if->get_proto_dev;
1209         rep_if->priv = __rep_if->priv;
1210
1211         rep_if->valid = true;
1212 }
1213 EXPORT_SYMBOL(mlx5_eswitch_register_vport_rep);
1214
1215 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1216                                        int vport_index, u8 rep_type)
1217 {
1218         struct mlx5_esw_offload *offloads = &esw->offloads;
1219         struct mlx5_eswitch_rep *rep;
1220
1221         rep = &offloads->vport_reps[vport_index];
1222
1223         if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1224                 rep->rep_if[rep_type].unload(rep);
1225
1226         rep->rep_if[rep_type].valid = false;
1227 }
1228 EXPORT_SYMBOL(mlx5_eswitch_unregister_vport_rep);
1229
1230 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1231 {
1232 #define UPLINK_REP_INDEX 0
1233         struct mlx5_esw_offload *offloads = &esw->offloads;
1234         struct mlx5_eswitch_rep *rep;
1235
1236         rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1237         return rep->rep_if[rep_type].priv;
1238 }
1239
1240 void *mlx5_eswitch_get_proto_dev(struct mlx5_eswitch *esw,
1241                                  int vport,
1242                                  u8 rep_type)
1243 {
1244         struct mlx5_esw_offload *offloads = &esw->offloads;
1245         struct mlx5_eswitch_rep *rep;
1246
1247         if (vport == FDB_UPLINK_VPORT)
1248                 vport = UPLINK_REP_INDEX;
1249
1250         rep = &offloads->vport_reps[vport];
1251
1252         if (rep->rep_if[rep_type].valid &&
1253             rep->rep_if[rep_type].get_proto_dev)
1254                 return rep->rep_if[rep_type].get_proto_dev(rep);
1255         return NULL;
1256 }
1257 EXPORT_SYMBOL(mlx5_eswitch_get_proto_dev);
1258
1259 void *mlx5_eswitch_uplink_get_proto_dev(struct mlx5_eswitch *esw, u8 rep_type)
1260 {
1261         return mlx5_eswitch_get_proto_dev(esw, UPLINK_REP_INDEX, rep_type);
1262 }
1263 EXPORT_SYMBOL(mlx5_eswitch_uplink_get_proto_dev);
1264
1265 struct mlx5_eswitch_rep *mlx5_eswitch_vport_rep(struct mlx5_eswitch *esw,
1266                                                 int vport)
1267 {
1268         return &esw->offloads.vport_reps[vport];
1269 }
1270 EXPORT_SYMBOL(mlx5_eswitch_vport_rep);