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